net/9p: add privport option to 9p tcp transport

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>
This commit is contained in:
Jim Garlick 2013-05-29 12:15:07 -07:00 committed by Eric Van Hensbergen
parent 2315cb1401
commit 2f28c8b31d
2 changed files with 42 additions and 1 deletions

View 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

View 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);