int rfd;
int wfd;
u16 port;
+ int privport;
};
/**
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},
};
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;
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,
case Opt_wfdno:
opts->wfd = option;
break;
+ case Opt_privport:
+ opts->privport = 1;
+ break;
default:
continue;
}
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)
{
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);