[NETFILTER]: x_tables: return new table from {arp,ip,ip6}t_register_table()
[safe/jmp/linux-2.6] / net / 9p / trans_fd.c
1 /*
2  * linux/fs/9p/trans_fd.c
3  *
4  * Fd transport layer.  Includes deprecated socket layer.
5  *
6  *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
7  *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
8  *  Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com>
9  *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License version 2
13  *  as published by the Free Software Foundation.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to:
22  *  Free Software Foundation
23  *  51 Franklin Street, Fifth Floor
24  *  Boston, MA  02111-1301  USA
25  *
26  */
27
28 #include <linux/in.h>
29 #include <linux/module.h>
30 #include <linux/net.h>
31 #include <linux/ipv6.h>
32 #include <linux/errno.h>
33 #include <linux/kernel.h>
34 #include <linux/un.h>
35 #include <linux/uaccess.h>
36 #include <linux/inet.h>
37 #include <linux/idr.h>
38 #include <linux/file.h>
39 #include <linux/parser.h>
40 #include <net/9p/9p.h>
41 #include <net/9p/transport.h>
42
43 #define P9_PORT 564
44 #define MAX_SOCK_BUF (64*1024)
45
46
47 struct p9_fd_opts {
48         int rfd;
49         int wfd;
50         u16 port;
51 };
52
53 struct p9_trans_fd {
54         struct file *rd;
55         struct file *wr;
56 };
57
58 /*
59   * Option Parsing (code inspired by NFS code)
60   *  - a little lazy - parse all fd-transport options
61   */
62
63 enum {
64         /* Options that take integer arguments */
65         Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
66 };
67
68 static match_table_t tokens = {
69         {Opt_port, "port=%u"},
70         {Opt_rfdno, "rfdno=%u"},
71         {Opt_wfdno, "wfdno=%u"},
72         {Opt_err, NULL},
73 };
74
75 /**
76  * v9fs_parse_options - parse mount options into session structure
77  * @options: options string passed from mount
78  * @v9ses: existing v9fs session information
79  *
80  */
81
82 static void parse_opts(char *options, struct p9_fd_opts *opts)
83 {
84         char *p;
85         substring_t args[MAX_OPT_ARGS];
86         int option;
87         int ret;
88
89         opts->port = P9_PORT;
90         opts->rfd = ~0;
91         opts->wfd = ~0;
92
93         if (!options)
94                 return;
95
96         while ((p = strsep(&options, ",")) != NULL) {
97                 int token;
98                 if (!*p)
99                         continue;
100                 token = match_token(p, tokens, args);
101                 ret = match_int(&args[0], &option);
102                 if (ret < 0) {
103                         P9_DPRINTK(P9_DEBUG_ERROR,
104                          "integer field, but no integer?\n");
105                         continue;
106                 }
107                 switch (token) {
108                 case Opt_port:
109                         opts->port = option;
110                         break;
111                 case Opt_rfdno:
112                         opts->rfd = option;
113                         break;
114                 case Opt_wfdno:
115                         opts->wfd = option;
116                         break;
117                 default:
118                         continue;
119                 }
120         }
121 }
122
123 static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd)
124 {
125         struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
126                                            GFP_KERNEL);
127         if (!ts)
128                 return -ENOMEM;
129
130         ts->rd = fget(rfd);
131         ts->wr = fget(wfd);
132         if (!ts->rd || !ts->wr) {
133                 if (ts->rd)
134                         fput(ts->rd);
135                 if (ts->wr)
136                         fput(ts->wr);
137                 kfree(ts);
138                 return -EIO;
139         }
140
141         trans->priv = ts;
142         trans->status = Connected;
143
144         return 0;
145 }
146
147 static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
148 {
149         int fd, ret;
150
151         csocket->sk->sk_allocation = GFP_NOIO;
152         fd = sock_map_fd(csocket);
153         if (fd < 0) {
154                 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
155                 return fd;
156         }
157
158         ret = p9_fd_open(trans, fd, fd);
159         if (ret < 0) {
160                 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
161                 sockfd_put(csocket);
162                 return ret;
163         }
164
165         ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
166
167         return 0;
168 }
169
170 /**
171  * p9_fd_read- read from a fd
172  * @v9ses: session information
173  * @v: buffer to receive data into
174  * @len: size of receive buffer
175  *
176  */
177 static int p9_fd_read(struct p9_trans *trans, void *v, int len)
178 {
179         int ret;
180         struct p9_trans_fd *ts = NULL;
181
182         if (trans && trans->status != Disconnected)
183                 ts = trans->priv;
184
185         if (!ts)
186                 return -EREMOTEIO;
187
188         if (!(ts->rd->f_flags & O_NONBLOCK))
189                 P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
190
191         ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
192         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
193                 trans->status = Disconnected;
194         return ret;
195 }
196
197 /**
198  * p9_fd_write - write to a socket
199  * @v9ses: session information
200  * @v: buffer to send data from
201  * @len: size of send buffer
202  *
203  */
204 static int p9_fd_write(struct p9_trans *trans, void *v, int len)
205 {
206         int ret;
207         mm_segment_t oldfs;
208         struct p9_trans_fd *ts = NULL;
209
210         if (trans && trans->status != Disconnected)
211                 ts = trans->priv;
212
213         if (!ts)
214                 return -EREMOTEIO;
215
216         if (!(ts->wr->f_flags & O_NONBLOCK))
217                 P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
218
219         oldfs = get_fs();
220         set_fs(get_ds());
221         /* The cast to a user pointer is valid due to the set_fs() */
222         ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
223         set_fs(oldfs);
224
225         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
226                 trans->status = Disconnected;
227         return ret;
228 }
229
230 static unsigned int
231 p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
232 {
233         int ret, n;
234         struct p9_trans_fd *ts = NULL;
235         mm_segment_t oldfs;
236
237         if (trans && trans->status == Connected)
238                 ts = trans->priv;
239
240         if (!ts)
241                 return -EREMOTEIO;
242
243         if (!ts->rd->f_op || !ts->rd->f_op->poll)
244                 return -EIO;
245
246         if (!ts->wr->f_op || !ts->wr->f_op->poll)
247                 return -EIO;
248
249         oldfs = get_fs();
250         set_fs(get_ds());
251
252         ret = ts->rd->f_op->poll(ts->rd, pt);
253         if (ret < 0)
254                 goto end;
255
256         if (ts->rd != ts->wr) {
257                 n = ts->wr->f_op->poll(ts->wr, pt);
258                 if (n < 0) {
259                         ret = n;
260                         goto end;
261                 }
262                 ret = (ret & ~POLLOUT) | (n & ~POLLIN);
263         }
264
265 end:
266         set_fs(oldfs);
267         return ret;
268 }
269
270 /**
271  * p9_sock_close - shutdown socket
272  * @trans: private socket structure
273  *
274  */
275 static void p9_fd_close(struct p9_trans *trans)
276 {
277         struct p9_trans_fd *ts;
278
279         if (!trans)
280                 return;
281
282         ts = xchg(&trans->priv, NULL);
283
284         if (!ts)
285                 return;
286
287         trans->status = Disconnected;
288         if (ts->rd)
289                 fput(ts->rd);
290         if (ts->wr)
291                 fput(ts->wr);
292         kfree(ts);
293 }
294
295 static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
296 {
297         int err;
298         struct p9_trans *trans;
299         struct socket *csocket;
300         struct sockaddr_in sin_server;
301         struct p9_fd_opts opts;
302
303         parse_opts(args, &opts);
304
305         csocket = NULL;
306         trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
307         if (!trans)
308                 return ERR_PTR(-ENOMEM);
309
310         trans->write = p9_fd_write;
311         trans->read = p9_fd_read;
312         trans->close = p9_fd_close;
313         trans->poll = p9_fd_poll;
314
315         sin_server.sin_family = AF_INET;
316         sin_server.sin_addr.s_addr = in_aton(addr);
317         sin_server.sin_port = htons(opts.port);
318         sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
319
320         if (!csocket) {
321                 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
322                 err = -EIO;
323                 goto error;
324         }
325
326         err = csocket->ops->connect(csocket,
327                                     (struct sockaddr *)&sin_server,
328                                     sizeof(struct sockaddr_in), 0);
329         if (err < 0) {
330                 P9_EPRINTK(KERN_ERR,
331                         "p9_trans_tcp: problem connecting socket to %s\n",
332                         addr);
333                 goto error;
334         }
335
336         err = p9_socket_open(trans, csocket);
337         if (err < 0)
338                 goto error;
339
340         return trans;
341
342 error:
343         if (csocket)
344                 sock_release(csocket);
345
346         kfree(trans);
347         return ERR_PTR(err);
348 }
349
350 static struct p9_trans *p9_trans_create_unix(const char *addr, char *args)
351 {
352         int err;
353         struct socket *csocket;
354         struct sockaddr_un sun_server;
355         struct p9_trans *trans;
356
357         csocket = NULL;
358         trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
359         if (!trans)
360                 return ERR_PTR(-ENOMEM);
361
362         trans->write = p9_fd_write;
363         trans->read = p9_fd_read;
364         trans->close = p9_fd_close;
365         trans->poll = p9_fd_poll;
366
367         if (strlen(addr) > UNIX_PATH_MAX) {
368                 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
369                         addr);
370                 err = -ENAMETOOLONG;
371                 goto error;
372         }
373
374         sun_server.sun_family = PF_UNIX;
375         strcpy(sun_server.sun_path, addr);
376         sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
377         err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
378                         sizeof(struct sockaddr_un) - 1, 0);
379         if (err < 0) {
380                 P9_EPRINTK(KERN_ERR,
381                         "p9_trans_unix: problem connecting socket: %s: %d\n",
382                         addr, err);
383                 goto error;
384         }
385
386         err = p9_socket_open(trans, csocket);
387         if (err < 0)
388                 goto error;
389
390         return trans;
391
392 error:
393         if (csocket)
394                 sock_release(csocket);
395
396         kfree(trans);
397         return ERR_PTR(err);
398 }
399
400 static struct p9_trans *p9_trans_create_fd(const char *name, char *args)
401 {
402         int err;
403         struct p9_trans *trans;
404         struct p9_fd_opts opts;
405
406         parse_opts(args, &opts);
407
408         if (opts.rfd == ~0 || opts.wfd == ~0) {
409                 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
410                 return ERR_PTR(-ENOPROTOOPT);
411         }
412
413         trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
414         if (!trans)
415                 return ERR_PTR(-ENOMEM);
416
417         trans->write = p9_fd_write;
418         trans->read = p9_fd_read;
419         trans->close = p9_fd_close;
420         trans->poll = p9_fd_poll;
421
422         err = p9_fd_open(trans, opts.rfd, opts.wfd);
423         if (err < 0)
424                 goto error;
425
426         return trans;
427
428 error:
429         kfree(trans);
430         return ERR_PTR(err);
431 }
432
433 static struct p9_trans_module p9_tcp_trans = {
434         .name = "tcp",
435         .maxsize = MAX_SOCK_BUF,
436         .def = 1,
437         .create = p9_trans_create_tcp,
438 };
439
440 static struct p9_trans_module p9_unix_trans = {
441         .name = "unix",
442         .maxsize = MAX_SOCK_BUF,
443         .def = 0,
444         .create = p9_trans_create_unix,
445 };
446
447 static struct p9_trans_module p9_fd_trans = {
448         .name = "fd",
449         .maxsize = MAX_SOCK_BUF,
450         .def = 0,
451         .create = p9_trans_create_fd,
452 };
453
454 static int __init p9_trans_fd_init(void)
455 {
456         v9fs_register_trans(&p9_tcp_trans);
457         v9fs_register_trans(&p9_unix_trans);
458         v9fs_register_trans(&p9_fd_trans);
459
460         return 1;
461 }
462
463 static void __exit p9_trans_fd_exit(void) {
464         printk(KERN_ERR "Removal of 9p transports not implemented\n");
465         BUG();
466 }
467
468 module_init(p9_trans_fd_init);
469 module_exit(p9_trans_fd_exit);
470
471 MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
472 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
473 MODULE_LICENSE("GPL");