aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-cdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/core-cdev.c')
-rw-r--r--drivers/firewire/core-cdev.c39
1 files changed, 33 insertions, 6 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 231e6ee5ba4..4eeaed57e21 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -35,6 +35,7 @@
35#include <linux/preempt.h> 35#include <linux/preempt.h>
36#include <linux/sched.h> 36#include <linux/sched.h>
37#include <linux/spinlock.h> 37#include <linux/spinlock.h>
38#include <linux/string.h>
38#include <linux/time.h> 39#include <linux/time.h>
39#include <linux/uaccess.h> 40#include <linux/uaccess.h>
40#include <linux/vmalloc.h> 41#include <linux/vmalloc.h>
@@ -595,14 +596,22 @@ static int ioctl_send_request(struct client *client, void *buffer)
595 client->device->max_speed); 596 client->device->max_speed);
596} 597}
597 598
599static inline bool is_fcp_request(struct fw_request *request)
600{
601 return request == NULL;
602}
603
598static void release_request(struct client *client, 604static void release_request(struct client *client,
599 struct client_resource *resource) 605 struct client_resource *resource)
600{ 606{
601 struct inbound_transaction_resource *r = container_of(resource, 607 struct inbound_transaction_resource *r = container_of(resource,
602 struct inbound_transaction_resource, resource); 608 struct inbound_transaction_resource, resource);
603 609
604 fw_send_response(client->device->card, r->request, 610 if (is_fcp_request(r->request))
605 RCODE_CONFLICT_ERROR); 611 kfree(r->data);
612 else
613 fw_send_response(client->device->card, r->request,
614 RCODE_CONFLICT_ERROR);
606 kfree(r); 615 kfree(r);
607} 616}
608 617
@@ -615,6 +624,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
615 struct address_handler_resource *handler = callback_data; 624 struct address_handler_resource *handler = callback_data;
616 struct inbound_transaction_resource *r; 625 struct inbound_transaction_resource *r;
617 struct inbound_transaction_event *e; 626 struct inbound_transaction_event *e;
627 void *fcp_frame = NULL;
618 int ret; 628 int ret;
619 629
620 r = kmalloc(sizeof(*r), GFP_ATOMIC); 630 r = kmalloc(sizeof(*r), GFP_ATOMIC);
@@ -626,6 +636,18 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
626 r->data = payload; 636 r->data = payload;
627 r->length = length; 637 r->length = length;
628 638
639 if (is_fcp_request(request)) {
640 /*
641 * FIXME: Let core-transaction.c manage a
642 * single reference-counted copy?
643 */
644 fcp_frame = kmemdup(payload, length, GFP_ATOMIC);
645 if (fcp_frame == NULL)
646 goto failed;
647
648 r->data = fcp_frame;
649 }
650
629 r->resource.release = release_request; 651 r->resource.release = release_request;
630 ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); 652 ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
631 if (ret < 0) 653 if (ret < 0)
@@ -639,13 +661,16 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
639 e->request.closure = handler->closure; 661 e->request.closure = handler->closure;
640 662
641 queue_event(handler->client, &e->event, 663 queue_event(handler->client, &e->event,
642 &e->request, sizeof(e->request), payload, length); 664 &e->request, sizeof(e->request), r->data, length);
643 return; 665 return;
644 666
645 failed: 667 failed:
646 kfree(r); 668 kfree(r);
647 kfree(e); 669 kfree(e);
648 fw_send_response(card, request, RCODE_CONFLICT_ERROR); 670 kfree(fcp_frame);
671
672 if (!is_fcp_request(request))
673 fw_send_response(card, request, RCODE_CONFLICT_ERROR);
649} 674}
650 675
651static void release_address_handler(struct client *client, 676static void release_address_handler(struct client *client,
@@ -715,14 +740,16 @@ static int ioctl_send_response(struct client *client, void *buffer)
715 740
716 r = container_of(resource, struct inbound_transaction_resource, 741 r = container_of(resource, struct inbound_transaction_resource,
717 resource); 742 resource);
743 if (is_fcp_request(r->request))
744 goto out;
745
718 if (request->length < r->length) 746 if (request->length < r->length)
719 r->length = request->length; 747 r->length = request->length;
720
721 if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) { 748 if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
722 ret = -EFAULT; 749 ret = -EFAULT;
750 kfree(r->request);
723 goto out; 751 goto out;
724 } 752 }
725
726 fw_send_response(client->device->card, r->request, request->rcode); 753 fw_send_response(client->device->card, r->request, request->rcode);
727 out: 754 out:
728 kfree(r); 755 kfree(r);