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