]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blob - net/can/canethgw.c
Report errors in device registration
[can-eth-gw-linux.git] / net / can / canethgw.c
1 /*
2  * Copyright: (c) 2012 Czech Technical University in Prague
3  *
4  * Authors:
5  *      Radek Matějka <radek.matejka@gmail.com>
6  *      Michal Sojka  <sojkam1@fel.cvut.cz>
7  *
8  * Funded by: Volkswagen Group Research
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version
13  * 2 of the License, or (at your option) any later version.
14  */
15
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/kthread.h>
19 #include <linux/file.h>
20 #include <net/sock.h>
21 #include <linux/can.h>
22 #include <linux/miscdevice.h>
23 #include <linux/can/canethgw.h>
24
25 MODULE_LICENSE("GPL");
26
27 static int cegw_udp2can(void *data);
28 static int cegw_udp_send(struct socket *udp_sock, struct can_frame *cf,
29                 struct sockaddr_in* addr);
30 static int cegw_can2udp(void *data);
31 static int cegw_can_send(struct socket *can_sock, struct can_frame *cf);
32 static int cegw_thread_start(void *data);
33 static int cegw_thread_stop(struct cegw_job *job);
34 static void cegw_job_release(struct kref *ref);
35
36 static int cegw_udp_send(struct socket *udp_sock, struct can_frame *cf, struct sockaddr_in* addr)
37 {
38         struct msghdr mh;
39         struct kvec vec;
40         int err;
41
42         mh.msg_name = addr;
43         mh.msg_namelen = sizeof(*addr);
44         mh.msg_control = NULL;
45         mh.msg_controllen = 0;
46         mh.msg_flags = 0;
47
48         vec.iov_base = cf;
49         vec.iov_len = sizeof(*cf);
50
51         err = kernel_sendmsg(udp_sock, &mh, &vec, 1, sizeof(*cf));
52
53         return err;
54 }
55
56 static int cegw_can_send(struct socket* can_sock, struct can_frame* cf)
57 {
58         struct msghdr mh;
59         struct kvec vec;
60         int err;
61
62         mh.msg_name = NULL;
63         mh.msg_namelen = 0;
64         mh.msg_control = NULL;
65         mh.msg_controllen = 0;
66         mh.msg_flags = 0;
67
68         vec.iov_base = cf;
69         vec.iov_len = sizeof(*cf);
70
71         err = kernel_sendmsg(can_sock, &mh, &vec, 1, sizeof(*cf));
72
73         return err;
74 }
75
76 /**
77  * cegw_udp2can - performs udp->can routing
78  *
79  * This function is run as a thread.
80  */
81 static int cegw_udp2can(void *data)
82 {
83         struct can_frame cf;
84         struct kvec vec;
85         struct msghdr mh;
86         struct cegw_job *job = (struct cegw_job *)data;
87         struct socket *udp_sock = NULL, *can_sock = NULL;
88         int ret = 0;
89
90         memset(&mh, 0, sizeof(mh));
91         udp_sock = job->udp_sock;
92         can_sock = job->can_sock;
93
94         while (1) {
95                 vec.iov_base = &cf;
96                 vec.iov_len = sizeof(cf);
97                 ret = kernel_recvmsg(udp_sock, &mh, &vec, 1,
98                                 sizeof(cf), 0);
99                 if (ret < 1)
100                         break;
101
102                 cf.can_id = be32_to_cpu(cf.can_id);
103                 cegw_can_send(can_sock, &cf);
104         }
105
106         cegw_thread_stop(job);
107         kref_put(&job->refcount, cegw_job_release);
108         do_exit(ret);
109 }
110
111 /**
112  * cegw_can2udp - performs can->udp routing
113  *
114  * This function is run as a thread.
115  */
116 static int cegw_can2udp(void* data)
117 {
118         struct msghdr mh;
119         struct kvec vec;
120         struct can_frame cf;
121         struct cegw_job* job = (struct cegw_job*)data;
122         struct socket* udp_sock = job->udp_sock;
123         struct socket* can_sock = job->can_sock;
124         int i;
125         int ret;
126
127         memset(&mh, 0, sizeof(mh));
128
129         while (1) {
130                 vec.iov_base = &cf;
131                 vec.iov_len = sizeof(cf);
132
133                 ret = kernel_recvmsg(can_sock, &mh, &vec, 1,
134                                            sizeof(cf), 0);
135                 if (ret < 1)
136                         break;
137
138                 cf.can_id = cpu_to_be32(cf.can_id);
139                 for (i=0; i<job->udp_dstcnt; i++) {
140                         cegw_udp_send(udp_sock, &cf, &job->udp_dst[i]);
141                 }
142         }
143
144         cegw_thread_stop(job);
145         kref_put(&job->refcount, cegw_job_release);
146         do_exit(ret);
147 }
148
149 static void cegw_job_release(struct kref *ref)
150 {
151         struct cegw_job *job = container_of(ref, struct cegw_job, refcount);
152
153         fput(job->can_sock->file);
154         fput(job->udp_sock->file);
155         kfree(job);
156 }
157
158 /**
159  * cegw_thread_start - start working threads
160  * @data: (struct cegw_job *) with sockets and udp addresses filled in
161  *
162  * Two threads are started. One is serving udp->can routing and the other
163  * can->udp.
164  */
165 static int cegw_thread_start(void *data)
166 {
167         struct task_struct *task = NULL;
168         struct cegw_job *job = (struct cegw_job *)data;
169
170         kref_init(&job->refcount);
171         kref_get(&job->refcount);
172
173         task = kthread_run(cegw_udp2can, data, "canethgw_udp2can");
174         if (IS_ERR(task)) {
175                 kref_sub(&job->refcount, 2, cegw_job_release);
176                 return -ENOMEM;
177         }
178
179         task = kthread_run(cegw_can2udp, data, "canethgw_can2udp");
180         if (IS_ERR(task)) {
181                 cegw_thread_stop(job);
182                 kref_put(&job->refcount, cegw_job_release);
183                 return -ENOMEM;
184         }
185
186         return 0;
187 }
188
189 /**
190  * cegw_thread_stop - stops threads
191  */
192 static int cegw_thread_stop(struct cegw_job *job)
193 {
194         int how = SHUT_RDWR;
195         struct sock *sk = NULL;
196         struct socket *udp_sock = job->udp_sock;
197         struct socket *can_sock = job->can_sock;
198
199         kernel_sock_shutdown(udp_sock, SHUT_RDWR);
200
201         /* PF_CAN sockets do not implement shutdown - do it manualy */
202         sk = can_sock->sk;
203         how++;
204         lock_sock(sk);
205         sk->sk_shutdown |= how;
206         sk->sk_state_change(sk);
207         release_sock(sk);
208
209         return 0;
210 }
211
212 static int cegw_open(struct inode *inode, struct file *file)
213 {
214         file->private_data = NULL;
215
216         if (try_module_get(THIS_MODULE) == false)
217                 return -EAGAIN;
218
219         return 0;
220 }
221
222 static int cegw_release(struct inode *inode, struct file *file)
223 {
224         struct cegw_job *job = (struct cegw_job *)file->private_data;
225
226         if (job) {
227                 cegw_thread_stop(job);
228         }
229
230         module_put(THIS_MODULE);
231         return 0;
232 }
233
234 /**
235  * cegw_ioctl_start - processes ioctl CEGW_IOCTL_START call
236  *
237  * The function takes over cegw_ioctl structure from userspace and
238  * prepares cegw_job structure. The cegw_job is stored in
239  * file->private_data and used by kernel threads to serve gateway
240  * functionality.
241  */
242 static long cegw_ioctl_start(struct file *file, unsigned long arg)
243 {
244         int i;
245         int err = 0;
246         __u32 dstcnt = 0;
247         __u32 addrlen = 0;
248         struct cegw_ioctl gwctl;
249         struct cegw_job *job = NULL;
250
251         err = copy_from_user(&gwctl, (void __user *)arg, sizeof(gwctl));
252         if (err != 0)
253                 return -EFAULT;
254
255         dstcnt = gwctl.udp_dstcnt;
256         addrlen = gwctl.udp_addrlen;
257
258         if (addrlen != sizeof(struct sockaddr_in))
259                 return -EAFNOSUPPORT;
260
261         /* */
262         job = kmalloc(GFP_KERNEL, sizeof(*job) + dstcnt*addrlen );
263         if (job == NULL)
264                 return -ENOMEM;
265
266         err = copy_from_user(&job->udp_dst, (void __user *)(arg + sizeof(struct cegw_ioctl)), dstcnt*addrlen);
267         if (err != 0) {
268                 kfree(job);
269                 return -EFAULT;
270         }
271
272         for (i=0; i<dstcnt; i++) {
273                 if (job->udp_dst[i].sin_family != AF_INET) {
274                         kfree(job);
275                         return -EAFNOSUPPORT;
276                 }
277         }
278
279         job->udp_sock = sockfd_lookup(gwctl.udp_sock, &err);
280         if (job->udp_sock == NULL) {
281                 kfree(job);
282                 return err;
283         }
284
285         job->can_sock = sockfd_lookup(gwctl.can_sock, &err);
286         if (job->can_sock == NULL) {
287                 fput(job->udp_sock->file);
288                 kfree(job);
289                 return err;
290         }
291
292         job->udp_dstcnt = dstcnt;
293
294         err = cegw_thread_start(job);
295         if (err != 0)
296                 return err;
297
298         file->private_data = job;
299         return 0;
300 }
301
302 static long cegw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
303 {
304         int err;
305
306         switch (cmd) {
307                 case CEGW_IOCTL_START:
308                         err = cegw_ioctl_start(file, arg);
309                         break;
310                 default:
311                         err = -EOPNOTSUPP;
312                         break;
313         }
314
315         return err;
316 }
317
318 static const struct file_operations cegw_fops = {
319         .owner = THIS_MODULE,
320         .open = cegw_open,
321         .release = cegw_release,
322         .unlocked_ioctl = cegw_ioctl
323 };
324
325 static struct miscdevice cegw_device = {
326         .minor = MISC_DYNAMIC_MINOR,
327         .name = "canethgw",
328         .fops = &cegw_fops
329 };
330
331 static int __init cegw_init(void)
332 {
333         return misc_register(&cegw_device);
334 }
335
336 static void __exit cegw_exit(void)
337 {
338         misc_deregister(&cegw_device);
339
340         return;
341 }
342
343 module_init(cegw_init);
344 module_exit(cegw_exit);