summaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-cdev.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-10 21:02:21 +0100
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-24 20:56:50 +0100
commit18e9b10fcdc090d3a38606958167d5923c7099b7 (patch)
treefd83055d908e8786afc9b3fbc791b57b2ba10c33 /drivers/firewire/fw-cdev.c
parent664d8010b170ae8b3ce9268b4f4da934d27b0491 (diff)
firewire: cdev: add closure to async stream ioctl
This changes the as yet unreleased FW_CDEV_IOC_SEND_STREAM_PACKET ioctl to generate an fw_cdev_event_response event just like the other two ioctls for asynchronous request transmission do. This way, clients get feedback on successful or unsuccessful transmission. This also adds input validation for length, tag, channel, sy, speed. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-cdev.c')
-rw-r--r--drivers/firewire/fw-cdev.c46
1 files changed, 19 insertions, 27 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 95a207545eb..7eb6594cc3e 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -522,7 +522,8 @@ static int init_request(struct client *client,
struct outbound_transaction_event *e;
int ret;
- if (request->length > 4096 || request->length > 512 << speed)
+ if (request->tcode != TCODE_STREAM_DATA &&
+ (request->length > 4096 || request->length > 512 << speed))
return -EIO;
e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
@@ -1247,36 +1248,27 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer)
return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
}
-struct stream_packet {
- struct fw_packet packet;
- u8 data[0];
-};
-
-static void send_stream_packet_done(struct fw_packet *packet,
- struct fw_card *card, int status)
-{
- kfree(container_of(packet, struct stream_packet, packet));
-}
-
static int ioctl_send_stream_packet(struct client *client, void *buffer)
{
- struct fw_cdev_send_stream_packet *request = buffer;
- struct stream_packet *p;
+ struct fw_cdev_send_stream_packet *p = buffer;
+ struct fw_cdev_send_request request;
+ int dest;
- p = kmalloc(sizeof(*p) + request->size, GFP_KERNEL);
- if (p == NULL)
- return -ENOMEM;
+ if (p->speed > client->device->card->link_speed ||
+ p->length > 1024 << p->speed)
+ return -EIO;
- if (request->data &&
- copy_from_user(p->data, u64_to_uptr(request->data), request->size)) {
- kfree(p);
- return -EFAULT;
- }
- fw_send_stream_packet(client->device->card, &p->packet,
- request->generation, request->speed,
- request->channel, request->sy, request->tag,
- p->data, request->size, send_stream_packet_done);
- return 0;
+ if (p->tag > 3 || p->channel > 63 || p->sy > 15)
+ return -EINVAL;
+
+ dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy);
+ request.tcode = TCODE_STREAM_DATA;
+ request.length = p->length;
+ request.closure = p->closure;
+ request.data = p->data;
+ request.generation = p->generation;
+
+ return init_request(client, &request, dest, p->speed);
}
static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {