]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blob - net/can/canethgw.c
1c99facc53e4cfd8d2056bbca8b56768ae7ee52d
[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         job = kmalloc(GFP_KERNEL, sizeof(*job) + dstcnt*addrlen );
262         if (job == NULL)
263                 return -ENOMEM;
264
265         err = copy_from_user(&job->udp_dst, (void __user *)(arg + sizeof(struct cegw_ioctl)), dstcnt*addrlen);
266         if (err != 0) {
267                 kfree(job);
268                 return -EFAULT;
269         }
270
271         for (i=0; i<dstcnt; i++) {
272                 if (job->udp_dst[i].sin_family != AF_INET) {
273                         kfree(job);
274                         return -EAFNOSUPPORT;
275                 }
276         }
277
278         job->udp_sock = sockfd_lookup(gwctl.udp_sock, &err);
279         if (job->udp_sock == NULL) {
280                 kfree(job);
281                 return err;
282         }
283
284         job->can_sock = sockfd_lookup(gwctl.can_sock, &err);
285         if (job->can_sock == NULL) {
286                 fput(job->udp_sock->file);
287                 kfree(job);
288                 return err;
289         }
290
291         job->udp_dstcnt = dstcnt;
292
293         err = cegw_thread_start(job);
294         if (err != 0)
295                 return err;
296
297         file->private_data = job;
298         return 0;
299 }
300
301 static long cegw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
302 {
303         int err;
304
305         switch (cmd) {
306                 case CEGW_IOCTL_START:
307                         err = cegw_ioctl_start(file, arg);
308                         break;
309                 default:
310                         err = -EOPNOTSUPP;
311                         break;
312         }
313
314         return err;
315 }
316
317 static const struct file_operations cegw_fops = {
318         .owner = THIS_MODULE,
319         .open = cegw_open,
320         .release = cegw_release,
321         .unlocked_ioctl = cegw_ioctl
322 };
323
324 static struct miscdevice cegw_device = {
325         .minor = MISC_DYNAMIC_MINOR,
326         .name = "canethgw",
327         .fops = &cegw_fops
328 };
329
330 static int __init cegw_init(void)
331 {
332         return misc_register(&cegw_device);
333 }
334
335 static void __exit cegw_exit(void)
336 {
337         misc_deregister(&cegw_device);
338
339         return;
340 }
341
342 module_init(cegw_init);
343 module_exit(cegw_exit);