net/9p: add privport option to 9p tcp transport
authorJim Garlick <garlick@llnl.gov>
Wed, 29 May 2013 19:15:07 +0000 (12:15 -0700)
committerEric Van Hensbergen <ericvh@gmail.com>
Mon, 8 Jul 2013 02:59:54 +0000 (21:59 -0500)
If the privport option is specified, the tcp transport binds local
address to a reserved port before connecting to the 9p server.

In some cases when 9P AUTH cannot be implemented, this is better than
nothing.

Signed-off-by: Jim Garlick <garlick@llnl.gov>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
include/net/9p/transport.h
net/9p/trans_fd.c

index adcbb20f65118be16489b65f2e087d3bf3128980..9a36d929711482da1f4090fb9e51c4ab9a261ffd 100644 (file)
@@ -26,6 +26,9 @@
 #ifndef NET_9P_TRANSPORT_H
 #define NET_9P_TRANSPORT_H
 
+#define P9_DEF_MIN_RESVPORT    (665U)
+#define P9_DEF_MAX_RESVPORT    (1023U)
+
 /**
  * struct p9_trans_module - transport module interface
  * @list: used to maintain a list of currently available transports
index 02efb25c295705141b3c477a2712864674ae42cc..3ffda1b3799b54340a0ba7851fa0f1c3cea6710c 100644 (file)
@@ -63,6 +63,7 @@ struct p9_fd_opts {
        int rfd;
        int wfd;
        u16 port;
+       int privport;
 };
 
 /**
@@ -87,12 +88,15 @@ struct p9_trans_fd {
 enum {
        /* Options that take integer arguments */
        Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
+       /* Options that take no arguments */
+       Opt_privport,
 };
 
 static const match_table_t tokens = {
        {Opt_port, "port=%u"},
        {Opt_rfdno, "rfdno=%u"},
        {Opt_wfdno, "wfdno=%u"},
+       {Opt_privport, "privport"},
        {Opt_err, NULL},
 };
 
@@ -161,6 +165,9 @@ static DEFINE_SPINLOCK(p9_poll_lock);
 static LIST_HEAD(p9_poll_pending_list);
 static DECLARE_WORK(p9_poll_work, p9_poll_workfn);
 
+static unsigned int p9_ipport_resv_min = P9_DEF_MIN_RESVPORT;
+static unsigned int p9_ipport_resv_max = P9_DEF_MAX_RESVPORT;
+
 static void p9_mux_poll_stop(struct p9_conn *m)
 {
        unsigned long flags;
@@ -741,7 +748,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
                if (!*p)
                        continue;
                token = match_token(p, tokens, args);
-               if (token != Opt_err) {
+               if ((token != Opt_err) && (token != Opt_privport)) {
                        r = match_int(&args[0], &option);
                        if (r < 0) {
                                p9_debug(P9_DEBUG_ERROR,
@@ -759,6 +766,9 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
                case Opt_wfdno:
                        opts->wfd = option;
                        break;
+               case Opt_privport:
+                       opts->privport = 1;
+                       break;
                default:
                        continue;
                }
@@ -898,6 +908,24 @@ static inline int valid_ipaddr4(const char *buf)
        return 0;
 }
 
+static int p9_bind_privport(struct socket *sock)
+{
+       struct sockaddr_in cl;
+       int port, err = -EINVAL;
+
+       memset(&cl, 0, sizeof(cl));
+       cl.sin_family = AF_INET;
+       cl.sin_addr.s_addr = INADDR_ANY;
+       for (port = p9_ipport_resv_max; port >= p9_ipport_resv_min; port--) {
+               cl.sin_port = htons((ushort)port);
+               err = kernel_bind(sock, (struct sockaddr *)&cl, sizeof(cl));
+               if (err != -EADDRINUSE)
+                       break;
+       }
+       return err;
+}
+
+
 static int
 p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
 {
@@ -926,6 +954,16 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
                return err;
        }
 
+       if (opts.privport) {
+               err = p9_bind_privport(csocket);
+               if (err < 0) {
+                       pr_err("%s (%d): problem binding to privport\n",
+                              __func__, task_pid_nr(current));
+                       sock_release(csocket);
+                       return err;
+               }
+       }
+
        err = csocket->ops->connect(csocket,
                                    (struct sockaddr *)&sin_server,
                                    sizeof(struct sockaddr_in), 0);