USB: usbmon: fix bug in mon_buff_area_shrink
authorAlan Stern <stern@rowland.harvard.edu>
Wed, 4 Nov 2009 16:35:53 +0000 (11:35 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 18 Nov 2009 00:46:34 +0000 (16:46 -0800)
This patch (as1299b) fixes a bug in an error-handling path of usbmon's
binary interface.  The storage area for URB data is divided into
fixed-size blocks.  If an URB's data can't be copied, the area
reserved for it should be decreased to the size of the truncated
information (rounded up to a block boundary).  Rounding up the amount
to be removed and subtracting it from the reserved size is definitely
the wrong thing to do.

Also, when the data for an isochronous URB can't be copied, we can
still copy the isoc packet descriptors.  In fact the current code does
copy the descriptors, but then sets the capture length to 0 so they
remain inaccessible.  The capture length should be reduced to the
length of the descriptors, not set to 0.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Pete Zaitcev <zaitcev@redhat.com>
CC: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/mon/mon_bin.c

index 9ed3e741bee160c7f2d71906810146f95f1da59a..10f3205798e880ce4f1351735666bac903e34398 100644 (file)
@@ -348,12 +348,12 @@ static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
 
 /*
  * Return a few (kilo-)bytes to the head of the buffer.
- * This is used if a DMA fetch fails.
+ * This is used if a data fetch fails.
  */
 static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
 {
 
-       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       /* size &= ~(PKT_ALIGN-1);  -- we're called with aligned size */
        rp->b_cnt -= size;
        if (rp->b_in < size)
                rp->b_in += rp->b_size;
@@ -433,6 +433,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
        unsigned int urb_length;
        unsigned int offset;
        unsigned int length;
+       unsigned int delta;
        unsigned int ndesc, lendesc;
        unsigned char dir;
        struct mon_bin_hdr *ep;
@@ -537,8 +538,10 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
        if (length != 0) {
                ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
                if (ep->flag_data != 0) {       /* Yes, it's 0x00, not '0' */
-                       ep->len_cap = 0;
-                       mon_buff_area_shrink(rp, length);
+                       delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+                       ep->len_cap -= length;
+                       delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+                       mon_buff_area_shrink(rp, delta);
                }
        } else {
                ep->flag_data = data_tag;