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