diff options
| author | Jim Garlick <garlick@llnl.gov> | 2013-05-29 12:15:07 -0700 | 
|---|---|---|
| committer | Eric Van Hensbergen <ericvh@gmail.com> | 2013-07-07 21:59:54 -0500 | 
| commit | 2f28c8b31dc501027d9aa6acf496c5941736312b (patch) | |
| tree | 30c8060085b6bb41d07534431b00d9733c78665a /net | |
| parent | 2315cb14010c4cb0eb7c1d19fcf90475e4688207 (diff) | |
| download | linux-2f28c8b31dc501027d9aa6acf496c5941736312b.tar.bz2 | |
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>
Diffstat (limited to 'net')
| -rw-r--r-- | net/9p/trans_fd.c | 40 | 
1 files changed, 39 insertions, 1 deletions
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 02efb25c2957..3ffda1b3799b 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -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);  |