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