diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2012-03-18 19:05:29 +0100 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2012-03-18 22:15:39 +0100 |
commit | 18d627113b830cda80792e96b28341bcd41cf40c (patch) | |
tree | 44281ec110668e9f7a583303b28ba2ca47012a20 /drivers | |
parent | 910e76c607546ead218de8b11c32597d6b8fe7e4 (diff) | |
download | linux-18d627113b830cda80792e96b28341bcd41cf40c.tar.gz linux-18d627113b830cda80792e96b28341bcd41cf40c.tar.bz2 linux-18d627113b830cda80792e96b28341bcd41cf40c.zip |
firewire: prevent dropping of completed iso packet header data
The buffer for the header data of completed iso packets has a fixed
size, so it is possible to configure a stream with a big interval
between interrupt packets or with big headers so that this buffer would
overflow. Previously, ohci.c would drop any data that would not fit,
but this could make unsuspecting applications believe that fewer than
the actual number of packets have completed.
Instead of dropping data, add calls to flush_iso_completion() so that
there are as many events as needed to report all of the data.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/core-cdev.c | 2 | ||||
-rw-r--r-- | drivers/firewire/ohci.c | 18 |
2 files changed, 10 insertions, 10 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index f5f5a9706fcc..4cb27dc542ce 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -51,7 +51,7 @@ /* * ABI version history is documented in linux/firewire-cdev.h. */ -#define FW_CDEV_KERNEL_VERSION 4 +#define FW_CDEV_KERNEL_VERSION 5 #define FW_CDEV_VERSION_EVENT_REQUEST2 4 #define FW_CDEV_VERSION_ALLOCATE_REGION_END 4 diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 07d3c8d58b30..632562667a01 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2689,7 +2689,7 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr) u32 *ctx_hdr; if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) - return; + flush_iso_completions(ctx); ctx_hdr = ctx->header + ctx->header_length; ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]); @@ -2826,16 +2826,16 @@ static int handle_it_packet(struct context *context, sync_it_packet_for_cpu(context, d); - if (ctx->header_length + 4 < PAGE_SIZE) { - ctx_hdr = ctx->header + ctx->header_length; - /* Present this value as big-endian to match the receive code */ - *ctx_hdr = cpu_to_be32( - ((u32)le16_to_cpu(pd->transfer_status) << 16) | - le16_to_cpu(pd->res_count)); - ctx->header_length += 4; - } + if (ctx->header_length + 4 > PAGE_SIZE) + flush_iso_completions(ctx); + ctx_hdr = ctx->header + ctx->header_length; ctx->last_timestamp = le16_to_cpu(last->res_count); + /* Present this value as big-endian to match the receive code */ + *ctx_hdr = cpu_to_be32((le16_to_cpu(pd->transfer_status) << 16) | + le16_to_cpu(pd->res_count)); + ctx->header_length += 4; + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) flush_iso_completions(ctx); |