summaryrefslogtreecommitdiff
path: root/drivers/usb/core/urb.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2013-06-28 09:38:12 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-24 15:52:43 -0700
commit10e232c597ac757e7f8600649f7e872e86de190f (patch)
treeb22a33022fad11706a62a926c0a462e2ea59265f /drivers/usb/core/urb.c
parenta6363463e8f5c7996aff6fa1285ff6c7cc3d3f6d (diff)
USB: check sg buffer size in usb_submit_urb
USB spec stats that short packet can only appear at the end of transfer. Because lost of HC(EHCI/UHCI/OHCI/...) can't build a full packet from discontinuous buffers, we introduce the limit in usb_submit_urb() to avoid such kind of bad sg buffers coming from driver. The limit might be a bit strict: - platform has iommu to do sg list mapping - some host controllers may support to build full packet from discontinuous buffers. But considered that most of HCs don't support that, and driver need work well or keep consistent on different HCs and ARCHs, we have to introduce the limit. Currently, only usbtest is reported to pass such sg buffers to HC, and other users(mass storage, usbfs) don't have the problem. We don't check it on USB wireless device, because: - wireless devices can't be attached to common USB bus(EHCI/UHCI/OHCI/...) - the max packet size of endpoint may be odd, and often can't devide 4KB which is a typical usage in usb mass storage application Reported-by: Konstantin Filatov <kfilatov@parallels.com> Reported-by: Denis V. Lunev <den@openvz.org> Cc: Felipe Balbi <balbi@ti.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/urb.c')
-rw-r--r--drivers/usb/core/urb.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 16927fa88fbd..e75115a04a2e 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -7,6 +7,7 @@
#include <linux/usb.h>
#include <linux/wait.h>
#include <linux/usb/hcd.h>
+#include <linux/scatterlist.h>
#define to_urb(d) container_of(d, struct urb, kref)
@@ -413,6 +414,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->iso_frame_desc[n].status = -EXDEV;
urb->iso_frame_desc[n].actual_length = 0;
}
+ } else if (dev->speed != USB_SPEED_WIRELESS && urb->num_sgs) {
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(urb->sg, sg, urb->num_sgs - 1, i)
+ if (sg->length % max)
+ return -EINVAL;
}
/* the I/O buffer must be mapped/unmapped, except when length=0 */