diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-03-10 16:02:21 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-03-24 15:56:50 -0400 |
commit | 18e9b10fcdc090d3a38606958167d5923c7099b7 (patch) | |
tree | fd83055d908e8786afc9b3fbc791b57b2ba10c33 /drivers/firewire/fw-cdev.c | |
parent | 664d8010b170ae8b3ce9268b4f4da934d27b0491 (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.c | 46 |
1 files changed, 19 insertions, 27 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 95a207545eb3..7eb6594cc3e5 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c | |||
@@ -522,7 +522,8 @@ static int init_request(struct client *client, | |||
522 | struct outbound_transaction_event *e; | 522 | struct outbound_transaction_event *e; |
523 | int ret; | 523 | int ret; |
524 | 524 | ||
525 | if (request->length > 4096 || request->length > 512 << speed) | 525 | if (request->tcode != TCODE_STREAM_DATA && |
526 | (request->length > 4096 || request->length > 512 << speed)) | ||
526 | return -EIO; | 527 | return -EIO; |
527 | 528 | ||
528 | e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL); | 529 | e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL); |
@@ -1247,36 +1248,27 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer) | |||
1247 | return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); | 1248 | return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); |
1248 | } | 1249 | } |
1249 | 1250 | ||
1250 | struct stream_packet { | ||
1251 | struct fw_packet packet; | ||
1252 | u8 data[0]; | ||
1253 | }; | ||
1254 | |||
1255 | static void send_stream_packet_done(struct fw_packet *packet, | ||
1256 | struct fw_card *card, int status) | ||
1257 | { | ||
1258 | kfree(container_of(packet, struct stream_packet, packet)); | ||
1259 | } | ||
1260 | |||
1261 | static int ioctl_send_stream_packet(struct client *client, void *buffer) | 1251 | static int ioctl_send_stream_packet(struct client *client, void *buffer) |
1262 | { | 1252 | { |
1263 | struct fw_cdev_send_stream_packet *request = buffer; | 1253 | struct fw_cdev_send_stream_packet *p = buffer; |
1264 | struct stream_packet *p; | 1254 | struct fw_cdev_send_request request; |
1255 | int dest; | ||
1265 | 1256 | ||
1266 | p = kmalloc(sizeof(*p) + request->size, GFP_KERNEL); | 1257 | if (p->speed > client->device->card->link_speed || |
1267 | if (p == NULL) | 1258 | p->length > 1024 << p->speed) |
1268 | return -ENOMEM; | 1259 | return -EIO; |
1269 | 1260 | ||
1270 | if (request->data && | 1261 | if (p->tag > 3 || p->channel > 63 || p->sy > 15) |
1271 | copy_from_user(p->data, u64_to_uptr(request->data), request->size)) { | 1262 | return -EINVAL; |
1272 | kfree(p); | 1263 | |
1273 | return -EFAULT; | 1264 | dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy); |
1274 | } | 1265 | request.tcode = TCODE_STREAM_DATA; |
1275 | fw_send_stream_packet(client->device->card, &p->packet, | 1266 | request.length = p->length; |
1276 | request->generation, request->speed, | 1267 | request.closure = p->closure; |
1277 | request->channel, request->sy, request->tag, | 1268 | request.data = p->data; |
1278 | p->data, request->size, send_stream_packet_done); | 1269 | request.generation = p->generation; |
1279 | return 0; | 1270 | |
1271 | return init_request(client, &request, dest, p->speed); | ||
1280 | } | 1272 | } |
1281 | 1273 | ||
1282 | static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { | 1274 | static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { |