]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blob - net/can/canethgw.c
532ce9540a9db78ea896835bf487c215de428df0
[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 enum msg_types {
28         CAN_FRAME,
29 };
30
31 struct cegw_job
32 {
33         struct kref refcount;
34         struct socket* can_sock;
35         struct socket* udp_sock;
36         u32  udp_dstcnt;
37         u32  udp_addrlen;
38         u8   udp_dst[0];
39 };
40
41 static int cegw_udp2can(void *data);
42 static int cegw_udp_send(struct socket *udp_sock, struct can_frame *cf,
43                 struct sockaddr* addr, int addrlen);
44 static int cegw_can2udp(void *data);
45 static int cegw_can_send(struct socket *can_sock, struct can_frame *cf);
46 static int cegw_thread_start(void *data);
47 static int cegw_thread_stop(struct cegw_job *job);
48 static void cegw_job_release(struct kref *ref);
49
50 static int cegw_udp_send(struct socket *udp_sock, struct can_frame *cf, struct sockaddr *addr,
51                 int addrlen)
52 {
53         struct msghdr mh;
54         struct kvec vec[2];
55         int err;
56         __u16 type = CAN_FRAME;
57
58         mh.msg_name = addr;
59         mh.msg_namelen = addrlen;
60         mh.msg_control = NULL;
61         mh.msg_controllen = 0;
62         mh.msg_flags = 0;
63
64         type = cpu_to_be16(type);
65         vec[0].iov_base = &type;
66         vec[0].iov_len = sizeof(type);
67         vec[1].iov_base = cf;
68         vec[1].iov_len = sizeof(*cf);
69
70         err = kernel_sendmsg(udp_sock, &mh, vec, 2, sizeof(type)+sizeof(*cf));
71
72         return err;
73 }
74
75 static int cegw_can_send(struct socket* can_sock, struct can_frame* cf)
76 {
77         struct msghdr mh;
78         struct kvec vec;
79         int err;
80
81         mh.msg_name = NULL;
82         mh.msg_namelen = 0;
83         mh.msg_control = NULL;
84         mh.msg_controllen = 0;
85         mh.msg_flags = 0;
86
87         vec.iov_base = cf;
88         vec.iov_len = sizeof(*cf);
89
90         err = kernel_sendmsg(can_sock, &mh, &vec, 1, sizeof(*cf));
91
92         return err;
93 }
94
95 /**
96  * cegw_udp2can - performs udp->can routing
97  *
98  * This function is run as a thread.
99  */
100 static int cegw_udp2can(void *data)
101 {
102         struct can_frame cf;
103         struct kvec vec[2];
104         struct msghdr mh;
105         struct cegw_job *job = (struct cegw_job *)data;
106         struct socket *udp_sock = NULL, *can_sock = NULL;
107         int ret = 0;
108         __u16 type;
109
110         memset(&mh, 0, sizeof(mh));
111         udp_sock = job->udp_sock;
112         can_sock = job->can_sock;
113
114         while (1) {
115                 vec[0].iov_base = &type;
116                 vec[0].iov_len = sizeof(type);
117                 vec[1].iov_base = &cf;
118                 vec[1].iov_len = sizeof(cf);
119                 ret = kernel_recvmsg(udp_sock, &mh, vec, 2,
120                                      sizeof(type) + sizeof(cf), 0);
121                 if (ret != sizeof(type) + sizeof(cf))
122                         break;
123
124                 type = be16_to_cpu(type);
125                 switch (type) {
126                 case CAN_FRAME:
127                         cf.can_id = be32_to_cpu(cf.can_id);
128                         cegw_can_send(can_sock, &cf);
129                 default:;
130                 }
131         }
132
133         cegw_thread_stop(job);
134         kref_put(&job->refcount, cegw_job_release);
135         do_exit(ret);
136 }
137
138 /**
139  * cegw_can2udp - performs can->udp routing
140  *
141  * This function is run as a thread.
142  */
143 static int cegw_can2udp(void* data)
144 {
145         struct msghdr mh;
146         struct kvec vec;
147         struct sockaddr *udst;
148         struct can_frame cf;
149         struct cegw_job* job = (struct cegw_job*)data;
150         struct socket* udp_sock = job->udp_sock;
151         struct socket* can_sock = job->can_sock;
152         int i;
153         int ret;
154
155         memset(&mh, 0, sizeof(mh));
156
157         while (1) {
158                 vec.iov_base = &cf;
159                 vec.iov_len = sizeof(cf);
160
161                 ret = kernel_recvmsg(can_sock, &mh, &vec, 1,
162                                      sizeof(cf), 0);
163                 if (ret != sizeof(cf))
164                         break;
165
166                 cf.can_id = cpu_to_be32(cf.can_id);
167                 for (i=0; i<job->udp_dstcnt; i++) {
168                         udst = (struct sockaddr *)(job->udp_dst + i*job->udp_addrlen);
169                         cegw_udp_send(udp_sock, &cf, udst, job->udp_addrlen);
170                 }
171         }
172
173         cegw_thread_stop(job);
174         kref_put(&job->refcount, cegw_job_release);
175         do_exit(ret);
176 }
177
178 static void cegw_job_release(struct kref *ref)
179 {
180         struct cegw_job *job = container_of(ref, struct cegw_job, refcount);
181
182         fput(job->can_sock->file);
183         fput(job->udp_sock->file);
184         kfree(job);
185 }
186
187 /**
188  * cegw_thread_start - start working threads
189  * @data: (struct cegw_job *) with sockets and udp addresses filled in
190  *
191  * Two threads are started. One is serving udp->can routing and the other
192  * can->udp.
193  */
194 static int cegw_thread_start(void *data)
195 {
196         struct task_struct *task = NULL;
197         struct cegw_job *job = (struct cegw_job *)data;
198
199         kref_get(&job->refcount);
200         task = kthread_run(cegw_udp2can, data, "canethgw_udp2can");
201         if (IS_ERR(task)) {
202                 kref_put(&job->refcount, cegw_job_release);
203                 return -ENOMEM;
204         }
205
206         kref_get(&job->refcount);
207         task = kthread_run(cegw_can2udp, data, "canethgw_can2udp");
208         if (IS_ERR(task)) {
209                 cegw_thread_stop(job);
210                 kref_put(&job->refcount, cegw_job_release);
211                 return -ENOMEM;
212         }
213
214         return 0;
215 }
216
217 /**
218  * cegw_thread_stop - stops threads
219  */
220 static int cegw_thread_stop(struct cegw_job *job)
221 {
222         int how = SHUT_RDWR;
223         struct sock *sk = NULL;
224         struct socket *udp_sock = job->udp_sock;
225         struct socket *can_sock = job->can_sock;
226
227         if (udp_sock)
228                 kernel_sock_shutdown(udp_sock, SHUT_RDWR);
229
230         /* PF_CAN sockets do not implement shutdown - do it manualy */
231         sk = can_sock->sk;
232         how++;
233         lock_sock(sk);
234         sk->sk_shutdown |= how;
235         sk->sk_state_change(sk);
236         release_sock(sk);
237
238         return 0;
239 }
240
241 static int cegw_open(struct inode *inode, struct file *file)
242 {
243         file->private_data = NULL;
244
245         if (try_module_get(THIS_MODULE) == false)
246                 return -EAGAIN;
247
248         return 0;
249 }
250
251 static int cegw_release(struct inode *inode, struct file *file)
252 {
253         struct cegw_job *job = (struct cegw_job *)file->private_data;
254
255         if (job) {
256                 cegw_thread_stop(job);
257         }
258         kref_put(&job->refcount, cegw_job_release);
259
260         module_put(THIS_MODULE);
261         return 0;
262 }
263
264 /**
265  * cegw_ioctl_start - processes ioctl CEGW_IOCTL_START call
266  *
267  * The function takes over cegw_ioctl structure from userspace and
268  * prepares cegw_job structure. The cegw_job is stored in
269  * file->private_data and used by kernel threads to serve gateway
270  * functionality.
271  */
272 static long cegw_ioctl_start(struct file *file, unsigned long arg)
273 {
274         int i;
275         int chckfam;
276         int err = 0;
277         __u32 dstcnt = 0;
278         __u32 addrlen = 0;
279         struct sockaddr *sa;
280         struct cegw_ioctl gwctl;
281         struct cegw_job *job = NULL;
282
283         err = copy_from_user(&gwctl, (void __user *)arg, sizeof(gwctl));
284         if (err != 0)
285                 return -EFAULT;
286
287         dstcnt = gwctl.udp_dstcnt;
288         addrlen = gwctl.udp_addrlen;
289
290         if (addrlen != sizeof(struct sockaddr_in) && addrlen != sizeof(struct sockaddr_in6))
291                 return -EAFNOSUPPORT;
292
293         /* ToDo: consider dstcnt maximum */
294         job = kmalloc(GFP_KERNEL, sizeof(*job) + dstcnt*addrlen);
295         if (job == NULL)
296                 return -ENOMEM;
297
298         err = copy_from_user(&job->udp_dst, (void __user *)(arg + sizeof(struct cegw_ioctl)), dstcnt*addrlen);
299         if (err != 0) {
300                 err = -EFAULT;
301                 goto err_free;
302         }
303
304         /* */
305         if (dstcnt > 0)
306                 sa = (struct sockaddr *)job->udp_dst;
307                 chckfam = sa->sa_family;
308
309         for (i=1; i<dstcnt; i++) {
310                 sa = (struct sockaddr *)(job->udp_dst + i*addrlen);
311                 if (sa->sa_family != chckfam) {
312                         err = -EAFNOSUPPORT;
313                         goto err_free;
314                 }
315         }
316
317         job->udp_sock = sockfd_lookup(gwctl.udp_sock, &err);
318         if (job->udp_sock == NULL)
319                 goto err_free;
320
321         job->can_sock = sockfd_lookup(gwctl.can_sock, &err);
322         if (job->can_sock == NULL)
323                 goto err_put_udp;
324
325         if (job->can_sock->ops->family != AF_CAN ||
326             job->can_sock->type != SOCK_RAW) {
327                 err = -EBADF;
328                 goto err_put_all;
329         }
330
331         kref_init(&job->refcount);
332
333         job->udp_dstcnt = dstcnt;
334         job->udp_addrlen = addrlen;
335
336         err = cegw_thread_start(job);
337         if (err != 0)
338                 return err; /* cegw_thread_start performs cleaup for us.  */
339
340         file->private_data = job;
341         return 0;
342
343 err_put_all:
344         fput(job->can_sock->file);
345 err_put_udp:
346         fput(job->udp_sock->file);
347 err_free:
348         kfree(job);
349         return err;
350 }
351
352 static long cegw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
353 {
354         long err;
355
356         switch (cmd) {
357                 case CEGW_IOCTL_START:
358                         err = cegw_ioctl_start(file, arg);
359                         break;
360                 default:
361                         err = -EOPNOTSUPP;
362                         break;
363         }
364
365         return err;
366 }
367
368 static const struct file_operations cegw_fops = {
369         .owner = THIS_MODULE,
370         .open = cegw_open,
371         .release = cegw_release,
372         .unlocked_ioctl = cegw_ioctl,
373         .compat_ioctl = cegw_ioctl,
374 };
375
376 static struct miscdevice cegw_device = {
377         .minor = MISC_DYNAMIC_MINOR,
378         .name = "canethgw",
379         .fops = &cegw_fops
380 };
381
382 static int __init cegw_init(void)
383 {
384         pr_info("can: can-eth gateway\n");
385         return misc_register(&cegw_device);
386 }
387
388 static void __exit cegw_exit(void)
389 {
390         misc_deregister(&cegw_device);
391
392         return;
393 }
394
395 module_init(cegw_init);
396 module_exit(cegw_exit);