]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/write.c
Added checking of values returned by copy_to/from_user
[lincan.git] / lincan / src / write.c
1 /* write.c
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
4  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
5  * email:pisa@cmp.felk.cvut.cz
6  * This software is released under the GPL-License.
7  * Version lincan-0.3  17 Jun 2004
8  */
9
10 #include "../include/can.h"
11 #include "../include/can_sysdep.h"
12 #include "../include/main.h"
13 #include "../include/write.h"
14
15 ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
16 {
17         struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
18         struct msgobj_t *obj;
19         struct canmsg_t msg_buff;
20         struct canque_ends_t *qends;
21         struct canque_edge_t *qedge;
22         struct canque_slot_t *slot;
23         int ret;
24         unsigned bytes_to_copy;
25
26         if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
27                 CANMSG("can_write: bad canuser magic\n");
28                 return -ENODEV;
29         }
30
31         if (length < sizeof(struct canmsg_t)) {
32                 DEBUGMSG("Trying to write less bytes than a CAN message,\n");
33                 DEBUGMSG("this will always return 0 !\n");
34                 return 0;
35         }
36         if (length > INT_MAX) {
37                 CANMSG("Trying to write more than is supported.\n");
38                 return -1;
39         }
40         if (length % sizeof(struct canmsg_t)) {
41                 CANMSG("The number of bytes requested to be written is not a multiple of\n");
42                 CANMSG("'sizeof(struct canmsg_t)', currently this is not allowed.\n");
43                 return -1;
44         } 
45
46         /* Initialize hardware pointers */
47         obj = canuser->msgobj;
48         if (obj == NULL) {
49                 CANMSG("Could not assign buffer structure\n");
50                 return -1;
51         }
52         qends = canuser->qends;
53
54
55         /* Prepare first message */
56         ret = copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
57         if(ret) return -EFAULT;
58
59         /* Automatic selection of extended format if ID>2047 */
60         if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT;
61         /* has been dependent on "extended" option */
62
63         /* If the output buffer is full, return immediately in case O_NONBLOCK
64          * has been specified or loop until space becomes available.
65          */
66         if ((ret=canque_get_inslot4id(qends, &qedge, &slot, 
67                         0, msg_buff.id, 0))<0){
68                 DEBUGMSG("Buffer is full\n");
69                 if(ret < -1)
70                         return -EIO;
71
72                 if (file->f_flags & O_NONBLOCK)
73                         return -EAGAIN;
74
75                 ret=canque_get_inslot4id_wait_kern(qends, &qedge, &slot, 
76                                                 0, msg_buff.id, 0);
77                 if(ret<0) {
78                         if (signal_pending(current))
79                                 return -EINTR;
80                         /*if (!can_timeout)*/
81                         return -EIO;
82                 }
83         }
84         slot->msg=msg_buff;
85         canque_put_inslot(qends, qedge, slot);
86         buffer += sizeof(struct canmsg_t);
87         bytes_to_copy = length-sizeof(struct canmsg_t);
88
89         /* 
90          * Try to send more messages
91          */
92         while (bytes_to_copy >= sizeof(struct canmsg_t)) {
93                 bytes_to_copy -= sizeof(struct canmsg_t);
94                 /* Prepare first message */
95                 ret = copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
96                 if(ret) return -EFAULT;
97
98                 /* Automatic selection of extended format if ID>2047 */
99                 if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT;
100                 /* has been dependent on "extended" option */
101
102                 /* Get slot */
103                 if(canque_get_inslot4id(qends, &qedge, &slot, 
104                         0, msg_buff.id, 0) < 0) break;
105                 slot->msg=msg_buff;
106                 canque_put_inslot(qends, qedge, slot);
107                 buffer += sizeof(struct canmsg_t);
108         }
109
110         if(file->f_flags & O_SYNC) {
111                 canque_sync_wait_kern(qends, qedge);
112         }
113         return length-bytes_to_copy;
114 }