|
@@ -32,6 +32,10 @@
|
|
#define RPCBIND_PROGRAM (100000u)
|
|
#define RPCBIND_PROGRAM (100000u)
|
|
#define RPCBIND_PORT (111u)
|
|
#define RPCBIND_PORT (111u)
|
|
|
|
|
|
|
|
+#define RPCBVERS_2 (2u)
|
|
|
|
+#define RPCBVERS_3 (3u)
|
|
|
|
+#define RPCBVERS_4 (4u)
|
|
|
|
+
|
|
enum {
|
|
enum {
|
|
RPCBPROC_NULL,
|
|
RPCBPROC_NULL,
|
|
RPCBPROC_SET,
|
|
RPCBPROC_SET,
|
|
@@ -64,6 +68,7 @@ enum {
|
|
#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
|
|
#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
|
|
|
|
|
|
static void rpcb_getport_done(struct rpc_task *, void *);
|
|
static void rpcb_getport_done(struct rpc_task *, void *);
|
|
|
|
+static void rpcb_map_release(void *data);
|
|
static struct rpc_program rpcb_program;
|
|
static struct rpc_program rpcb_program;
|
|
|
|
|
|
struct rpcbind_args {
|
|
struct rpcbind_args {
|
|
@@ -76,41 +81,73 @@ struct rpcbind_args {
|
|
const char * r_netid;
|
|
const char * r_netid;
|
|
const char * r_addr;
|
|
const char * r_addr;
|
|
const char * r_owner;
|
|
const char * r_owner;
|
|
|
|
+
|
|
|
|
+ int r_status;
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpc_procinfo rpcb_procedures2[];
|
|
static struct rpc_procinfo rpcb_procedures2[];
|
|
static struct rpc_procinfo rpcb_procedures3[];
|
|
static struct rpc_procinfo rpcb_procedures3[];
|
|
|
|
+static struct rpc_procinfo rpcb_procedures4[];
|
|
|
|
|
|
struct rpcb_info {
|
|
struct rpcb_info {
|
|
- int rpc_vers;
|
|
|
|
|
|
+ u32 rpc_vers;
|
|
struct rpc_procinfo * rpc_proc;
|
|
struct rpc_procinfo * rpc_proc;
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpcb_info rpcb_next_version[];
|
|
static struct rpcb_info rpcb_next_version[];
|
|
static struct rpcb_info rpcb_next_version6[];
|
|
static struct rpcb_info rpcb_next_version6[];
|
|
|
|
|
|
|
|
+static const struct rpc_call_ops rpcb_getport_ops = {
|
|
|
|
+ .rpc_call_done = rpcb_getport_done,
|
|
|
|
+ .rpc_release = rpcb_map_release,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
|
|
|
|
+{
|
|
|
|
+ xprt_clear_binding(xprt);
|
|
|
|
+ rpc_wake_up_status(&xprt->binding, status);
|
|
|
|
+}
|
|
|
|
+
|
|
static void rpcb_map_release(void *data)
|
|
static void rpcb_map_release(void *data)
|
|
{
|
|
{
|
|
struct rpcbind_args *map = data;
|
|
struct rpcbind_args *map = data;
|
|
|
|
|
|
|
|
+ rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status);
|
|
xprt_put(map->r_xprt);
|
|
xprt_put(map->r_xprt);
|
|
kfree(map);
|
|
kfree(map);
|
|
}
|
|
}
|
|
|
|
|
|
-static const struct rpc_call_ops rpcb_getport_ops = {
|
|
|
|
- .rpc_call_done = rpcb_getport_done,
|
|
|
|
- .rpc_release = rpcb_map_release,
|
|
|
|
|
|
+static const struct sockaddr_in rpcb_inaddr_loopback = {
|
|
|
|
+ .sin_family = AF_INET,
|
|
|
|
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
|
|
|
+ .sin_port = htons(RPCBIND_PORT),
|
|
};
|
|
};
|
|
|
|
|
|
-static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
|
|
|
|
|
|
+static const struct sockaddr_in6 rpcb_in6addr_loopback = {
|
|
|
|
+ .sin6_family = AF_INET6,
|
|
|
|
+ .sin6_addr = IN6ADDR_LOOPBACK_INIT,
|
|
|
|
+ .sin6_port = htons(RPCBIND_PORT),
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
|
|
|
|
+ size_t addrlen, u32 version)
|
|
{
|
|
{
|
|
- xprt_clear_binding(xprt);
|
|
|
|
- rpc_wake_up_status(&xprt->binding, status);
|
|
|
|
|
|
+ struct rpc_create_args args = {
|
|
|
|
+ .protocol = XPRT_TRANSPORT_UDP,
|
|
|
|
+ .address = addr,
|
|
|
|
+ .addrsize = addrlen,
|
|
|
|
+ .servername = "localhost",
|
|
|
|
+ .program = &rpcb_program,
|
|
|
|
+ .version = version,
|
|
|
|
+ .authflavor = RPC_AUTH_UNIX,
|
|
|
|
+ .flags = RPC_CLNT_CREATE_NOPING,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ return rpc_create(&args);
|
|
}
|
|
}
|
|
|
|
|
|
static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
|
|
static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
|
|
- size_t salen, int proto, u32 version,
|
|
|
|
- int privileged)
|
|
|
|
|
|
+ size_t salen, int proto, u32 version)
|
|
{
|
|
{
|
|
struct rpc_create_args args = {
|
|
struct rpc_create_args args = {
|
|
.protocol = proto,
|
|
.protocol = proto,
|
|
@@ -120,7 +157,8 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
|
|
.program = &rpcb_program,
|
|
.program = &rpcb_program,
|
|
.version = version,
|
|
.version = version,
|
|
.authflavor = RPC_AUTH_UNIX,
|
|
.authflavor = RPC_AUTH_UNIX,
|
|
- .flags = RPC_CLNT_CREATE_NOPING,
|
|
|
|
|
|
+ .flags = (RPC_CLNT_CREATE_NOPING |
|
|
|
|
+ RPC_CLNT_CREATE_NONPRIVPORT),
|
|
};
|
|
};
|
|
|
|
|
|
switch (srvaddr->sa_family) {
|
|
switch (srvaddr->sa_family) {
|
|
@@ -134,29 +172,72 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!privileged)
|
|
|
|
- args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
|
|
|
|
return rpc_create(&args);
|
|
return rpc_create(&args);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
|
|
|
|
+ u32 version, struct rpc_message *msg,
|
|
|
|
+ int *result)
|
|
|
|
+{
|
|
|
|
+ struct rpc_clnt *rpcb_clnt;
|
|
|
|
+ int error = 0;
|
|
|
|
+
|
|
|
|
+ *result = 0;
|
|
|
|
+
|
|
|
|
+ rpcb_clnt = rpcb_create_local(addr, addrlen, version);
|
|
|
|
+ if (!IS_ERR(rpcb_clnt)) {
|
|
|
|
+ error = rpc_call_sync(rpcb_clnt, msg, 0);
|
|
|
|
+ rpc_shutdown_client(rpcb_clnt);
|
|
|
|
+ } else
|
|
|
|
+ error = PTR_ERR(rpcb_clnt);
|
|
|
|
+
|
|
|
|
+ if (error < 0)
|
|
|
|
+ printk(KERN_WARNING "RPC: failed to contact local rpcbind "
|
|
|
|
+ "server (errno %d).\n", -error);
|
|
|
|
+ dprintk("RPC: registration status %d/%d\n", error, *result);
|
|
|
|
+
|
|
|
|
+ return error;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* rpcb_register - set or unset a port registration with the local rpcbind svc
|
|
* rpcb_register - set or unset a port registration with the local rpcbind svc
|
|
* @prog: RPC program number to bind
|
|
* @prog: RPC program number to bind
|
|
* @vers: RPC version number to bind
|
|
* @vers: RPC version number to bind
|
|
- * @prot: transport protocol to use to make this request
|
|
|
|
|
|
+ * @prot: transport protocol to register
|
|
* @port: port value to register
|
|
* @port: port value to register
|
|
- * @okay: result code
|
|
|
|
|
|
+ * @okay: OUT: result code
|
|
|
|
+ *
|
|
|
|
+ * RPC services invoke this function to advertise their contact
|
|
|
|
+ * information via the system's rpcbind daemon. RPC services
|
|
|
|
+ * invoke this function once for each [program, version, transport]
|
|
|
|
+ * tuple they wish to advertise.
|
|
|
|
+ *
|
|
|
|
+ * Callers may also unregister RPC services that are no longer
|
|
|
|
+ * available by setting the passed-in port to zero. This removes
|
|
|
|
+ * all registered transports for [program, version] from the local
|
|
|
|
+ * rpcbind database.
|
|
|
|
+ *
|
|
|
|
+ * Returns zero if the registration request was dispatched
|
|
|
|
+ * successfully and a reply was received. The rpcbind daemon's
|
|
|
|
+ * boolean result code is stored in *okay.
|
|
|
|
+ *
|
|
|
|
+ * Returns an errno value and sets *result to zero if there was
|
|
|
|
+ * some problem that prevented the rpcbind request from being
|
|
|
|
+ * dispatched, or if the rpcbind daemon did not respond within
|
|
|
|
+ * the timeout.
|
|
*
|
|
*
|
|
- * port == 0 means unregister, port != 0 means register.
|
|
|
|
|
|
+ * This function uses rpcbind protocol version 2 to contact the
|
|
|
|
+ * local rpcbind daemon.
|
|
*
|
|
*
|
|
- * This routine supports only rpcbind version 2.
|
|
|
|
|
|
+ * Registration works over both AF_INET and AF_INET6, and services
|
|
|
|
+ * registered via this function are advertised as available for any
|
|
|
|
+ * address. If the local rpcbind daemon is listening on AF_INET6,
|
|
|
|
+ * services registered via this function will be advertised on
|
|
|
|
+ * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
|
|
|
|
+ * addresses).
|
|
*/
|
|
*/
|
|
int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
|
int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
|
{
|
|
{
|
|
- struct sockaddr_in sin = {
|
|
|
|
- .sin_family = AF_INET,
|
|
|
|
- .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
|
|
|
- };
|
|
|
|
struct rpcbind_args map = {
|
|
struct rpcbind_args map = {
|
|
.r_prog = prog,
|
|
.r_prog = prog,
|
|
.r_vers = vers,
|
|
.r_vers = vers,
|
|
@@ -164,32 +245,159 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
|
|
.r_port = port,
|
|
.r_port = port,
|
|
};
|
|
};
|
|
struct rpc_message msg = {
|
|
struct rpc_message msg = {
|
|
- .rpc_proc = &rpcb_procedures2[port ?
|
|
|
|
- RPCBPROC_SET : RPCBPROC_UNSET],
|
|
|
|
.rpc_argp = &map,
|
|
.rpc_argp = &map,
|
|
.rpc_resp = okay,
|
|
.rpc_resp = okay,
|
|
};
|
|
};
|
|
- struct rpc_clnt *rpcb_clnt;
|
|
|
|
- int error = 0;
|
|
|
|
|
|
|
|
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
|
|
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
|
|
"rpcbind\n", (port ? "" : "un"),
|
|
"rpcbind\n", (port ? "" : "un"),
|
|
prog, vers, prot, port);
|
|
prog, vers, prot, port);
|
|
|
|
|
|
- rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
|
|
|
|
- sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1);
|
|
|
|
- if (IS_ERR(rpcb_clnt))
|
|
|
|
- return PTR_ERR(rpcb_clnt);
|
|
|
|
|
|
+ msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
|
|
|
|
+ if (port)
|
|
|
|
+ msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
|
|
|
|
|
|
- error = rpc_call_sync(rpcb_clnt, &msg, 0);
|
|
|
|
|
|
+ return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
|
|
|
|
+ sizeof(rpcb_inaddr_loopback),
|
|
|
|
+ RPCBVERS_2, &msg, okay);
|
|
|
|
+}
|
|
|
|
|
|
- rpc_shutdown_client(rpcb_clnt);
|
|
|
|
- if (error < 0)
|
|
|
|
- printk(KERN_WARNING "RPC: failed to contact local rpcbind "
|
|
|
|
- "server (errno %d).\n", -error);
|
|
|
|
- dprintk("RPC: registration status %d/%d\n", error, *okay);
|
|
|
|
|
|
+/*
|
|
|
|
+ * Fill in AF_INET family-specific arguments to register
|
|
|
|
+ */
|
|
|
|
+static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
|
|
|
|
+ struct rpc_message *msg)
|
|
|
|
+{
|
|
|
|
+ struct rpcbind_args *map = msg->rpc_argp;
|
|
|
|
+ unsigned short port = ntohs(address_to_register->sin_port);
|
|
|
|
+ char buf[32];
|
|
|
|
+
|
|
|
|
+ /* Construct AF_INET universal address */
|
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
|
+ NIPQUAD_FMT".%u.%u",
|
|
|
|
+ NIPQUAD(address_to_register->sin_addr.s_addr),
|
|
|
|
+ port >> 8, port & 0xff);
|
|
|
|
+ map->r_addr = buf;
|
|
|
|
+
|
|
|
|
+ dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
|
|
|
|
+ "local rpcbind\n", (port ? "" : "un"),
|
|
|
|
+ map->r_prog, map->r_vers,
|
|
|
|
+ map->r_addr, map->r_netid);
|
|
|
|
+
|
|
|
|
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
|
|
|
|
+ if (port)
|
|
|
|
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
|
|
|
|
+
|
|
|
|
+ return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
|
|
|
|
+ sizeof(rpcb_inaddr_loopback),
|
|
|
|
+ RPCBVERS_4, msg, msg->rpc_resp);
|
|
|
|
+}
|
|
|
|
|
|
- return error;
|
|
|
|
|
|
+/*
|
|
|
|
+ * Fill in AF_INET6 family-specific arguments to register
|
|
|
|
+ */
|
|
|
|
+static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
|
|
|
|
+ struct rpc_message *msg)
|
|
|
|
+{
|
|
|
|
+ struct rpcbind_args *map = msg->rpc_argp;
|
|
|
|
+ unsigned short port = ntohs(address_to_register->sin6_port);
|
|
|
|
+ char buf[64];
|
|
|
|
+
|
|
|
|
+ /* Construct AF_INET6 universal address */
|
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
|
+ NIP6_FMT".%u.%u",
|
|
|
|
+ NIP6(address_to_register->sin6_addr),
|
|
|
|
+ port >> 8, port & 0xff);
|
|
|
|
+ map->r_addr = buf;
|
|
|
|
+
|
|
|
|
+ dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
|
|
|
|
+ "local rpcbind\n", (port ? "" : "un"),
|
|
|
|
+ map->r_prog, map->r_vers,
|
|
|
|
+ map->r_addr, map->r_netid);
|
|
|
|
+
|
|
|
|
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
|
|
|
|
+ if (port)
|
|
|
|
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
|
|
|
|
+
|
|
|
|
+ return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
|
|
|
|
+ sizeof(rpcb_in6addr_loopback),
|
|
|
|
+ RPCBVERS_4, msg, msg->rpc_resp);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * rpcb_v4_register - set or unset a port registration with the local rpcbind
|
|
|
|
+ * @program: RPC program number of service to (un)register
|
|
|
|
+ * @version: RPC version number of service to (un)register
|
|
|
|
+ * @address: address family, IP address, and port to (un)register
|
|
|
|
+ * @netid: netid of transport protocol to (un)register
|
|
|
|
+ * @result: result code from rpcbind RPC call
|
|
|
|
+ *
|
|
|
|
+ * RPC services invoke this function to advertise their contact
|
|
|
|
+ * information via the system's rpcbind daemon. RPC services
|
|
|
|
+ * invoke this function once for each [program, version, address,
|
|
|
|
+ * netid] tuple they wish to advertise.
|
|
|
|
+ *
|
|
|
|
+ * Callers may also unregister RPC services that are no longer
|
|
|
|
+ * available by setting the port number in the passed-in address
|
|
|
|
+ * to zero. Callers pass a netid of "" to unregister all
|
|
|
|
+ * transport netids associated with [program, version, address].
|
|
|
|
+ *
|
|
|
|
+ * Returns zero if the registration request was dispatched
|
|
|
|
+ * successfully and a reply was received. The rpcbind daemon's
|
|
|
|
+ * result code is stored in *result.
|
|
|
|
+ *
|
|
|
|
+ * Returns an errno value and sets *result to zero if there was
|
|
|
|
+ * some problem that prevented the rpcbind request from being
|
|
|
|
+ * dispatched, or if the rpcbind daemon did not respond within
|
|
|
|
+ * the timeout.
|
|
|
|
+ *
|
|
|
|
+ * This function uses rpcbind protocol version 4 to contact the
|
|
|
|
+ * local rpcbind daemon. The local rpcbind daemon must support
|
|
|
|
+ * version 4 of the rpcbind protocol in order for these functions
|
|
|
|
+ * to register a service successfully.
|
|
|
|
+ *
|
|
|
|
+ * Supported netids include "udp" and "tcp" for UDP and TCP over
|
|
|
|
+ * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6,
|
|
|
|
+ * respectively.
|
|
|
|
+ *
|
|
|
|
+ * The contents of @address determine the address family and the
|
|
|
|
+ * port to be registered. The usual practice is to pass INADDR_ANY
|
|
|
|
+ * as the raw address, but specifying a non-zero address is also
|
|
|
|
+ * supported by this API if the caller wishes to advertise an RPC
|
|
|
|
+ * service on a specific network interface.
|
|
|
|
+ *
|
|
|
|
+ * Note that passing in INADDR_ANY does not create the same service
|
|
|
|
+ * registration as IN6ADDR_ANY. The former advertises an RPC
|
|
|
|
+ * service on any IPv4 address, but not on IPv6. The latter
|
|
|
|
+ * advertises the service on all IPv4 and IPv6 addresses.
|
|
|
|
+ */
|
|
|
|
+int rpcb_v4_register(const u32 program, const u32 version,
|
|
|
|
+ const struct sockaddr *address, const char *netid,
|
|
|
|
+ int *result)
|
|
|
|
+{
|
|
|
|
+ struct rpcbind_args map = {
|
|
|
|
+ .r_prog = program,
|
|
|
|
+ .r_vers = version,
|
|
|
|
+ .r_netid = netid,
|
|
|
|
+ .r_owner = RPCB_OWNER_STRING,
|
|
|
|
+ };
|
|
|
|
+ struct rpc_message msg = {
|
|
|
|
+ .rpc_argp = &map,
|
|
|
|
+ .rpc_resp = result,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ *result = 0;
|
|
|
|
+
|
|
|
|
+ switch (address->sa_family) {
|
|
|
|
+ case AF_INET:
|
|
|
|
+ return rpcb_register_netid4((struct sockaddr_in *)address,
|
|
|
|
+ &msg);
|
|
|
|
+ case AF_INET6:
|
|
|
|
+ return rpcb_register_netid6((struct sockaddr_in6 *)address,
|
|
|
|
+ &msg);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return -EAFNOSUPPORT;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -227,7 +435,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
|
|
__func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
|
|
__func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
|
|
|
|
|
|
rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
|
|
rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
|
|
- sizeof(*sin), prot, 2, 0);
|
|
|
|
|
|
+ sizeof(*sin), prot, RPCBVERS_2);
|
|
if (IS_ERR(rpcb_clnt))
|
|
if (IS_ERR(rpcb_clnt))
|
|
return PTR_ERR(rpcb_clnt);
|
|
return PTR_ERR(rpcb_clnt);
|
|
|
|
|
|
@@ -289,17 +497,16 @@ void rpcb_getport_async(struct rpc_task *task)
|
|
/* Autobind on cloned rpc clients is discouraged */
|
|
/* Autobind on cloned rpc clients is discouraged */
|
|
BUG_ON(clnt->cl_parent != clnt);
|
|
BUG_ON(clnt->cl_parent != clnt);
|
|
|
|
|
|
|
|
+ /* Put self on the wait queue to ensure we get notified if
|
|
|
|
+ * some other task is already attempting to bind the port */
|
|
|
|
+ rpc_sleep_on(&xprt->binding, task, NULL);
|
|
|
|
+
|
|
if (xprt_test_and_set_binding(xprt)) {
|
|
if (xprt_test_and_set_binding(xprt)) {
|
|
- status = -EAGAIN; /* tell caller to check again */
|
|
|
|
dprintk("RPC: %5u %s: waiting for another binder\n",
|
|
dprintk("RPC: %5u %s: waiting for another binder\n",
|
|
task->tk_pid, __func__);
|
|
task->tk_pid, __func__);
|
|
- goto bailout_nowake;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Put self on queue before sending rpcbind request, in case
|
|
|
|
- * rpcb_getport_done completes before we return from rpc_run_task */
|
|
|
|
- rpc_sleep_on(&xprt->binding, task, NULL);
|
|
|
|
-
|
|
|
|
/* Someone else may have bound if we slept */
|
|
/* Someone else may have bound if we slept */
|
|
if (xprt_bound(xprt)) {
|
|
if (xprt_bound(xprt)) {
|
|
status = 0;
|
|
status = 0;
|
|
@@ -338,7 +545,7 @@ void rpcb_getport_async(struct rpc_task *task)
|
|
task->tk_pid, __func__, bind_version);
|
|
task->tk_pid, __func__, bind_version);
|
|
|
|
|
|
rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
|
|
rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
|
|
- bind_version, 0);
|
|
|
|
|
|
+ bind_version);
|
|
if (IS_ERR(rpcb_clnt)) {
|
|
if (IS_ERR(rpcb_clnt)) {
|
|
status = PTR_ERR(rpcb_clnt);
|
|
status = PTR_ERR(rpcb_clnt);
|
|
dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
|
|
dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
|
|
@@ -361,15 +568,15 @@ void rpcb_getport_async(struct rpc_task *task)
|
|
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
|
|
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
|
|
map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
|
|
map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
|
|
map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
|
|
map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
|
|
|
|
+ map->r_status = -EIO;
|
|
|
|
|
|
child = rpcb_call_async(rpcb_clnt, map, proc);
|
|
child = rpcb_call_async(rpcb_clnt, map, proc);
|
|
rpc_release_client(rpcb_clnt);
|
|
rpc_release_client(rpcb_clnt);
|
|
if (IS_ERR(child)) {
|
|
if (IS_ERR(child)) {
|
|
- status = -EIO;
|
|
|
|
/* rpcb_map_release() has freed the arguments */
|
|
/* rpcb_map_release() has freed the arguments */
|
|
dprintk("RPC: %5u %s: rpc_run_task failed\n",
|
|
dprintk("RPC: %5u %s: rpc_run_task failed\n",
|
|
task->tk_pid, __func__);
|
|
task->tk_pid, __func__);
|
|
- goto bailout_nofree;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
rpc_put_task(child);
|
|
rpc_put_task(child);
|
|
|
|
|
|
@@ -378,7 +585,6 @@ void rpcb_getport_async(struct rpc_task *task)
|
|
|
|
|
|
bailout_nofree:
|
|
bailout_nofree:
|
|
rpcb_wake_rpcbind_waiters(xprt, status);
|
|
rpcb_wake_rpcbind_waiters(xprt, status);
|
|
-bailout_nowake:
|
|
|
|
task->tk_status = status;
|
|
task->tk_status = status;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(rpcb_getport_async);
|
|
EXPORT_SYMBOL_GPL(rpcb_getport_async);
|
|
@@ -417,9 +623,13 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
|
|
dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
|
|
dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
|
|
child->tk_pid, status, map->r_port);
|
|
child->tk_pid, status, map->r_port);
|
|
|
|
|
|
- rpcb_wake_rpcbind_waiters(xprt, status);
|
|
|
|
|
|
+ map->r_status = status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * XDR functions for rpcbind
|
|
|
|
+ */
|
|
|
|
+
|
|
static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
|
|
static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
|
|
struct rpcbind_args *rpcb)
|
|
struct rpcbind_args *rpcb)
|
|
{
|
|
{
|
|
@@ -438,7 +648,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
|
|
unsigned short *portp)
|
|
unsigned short *portp)
|
|
{
|
|
{
|
|
*portp = (unsigned short) ntohl(*p++);
|
|
*portp = (unsigned short) ntohl(*p++);
|
|
- dprintk("RPC: rpcb_decode_getport result %u\n",
|
|
|
|
|
|
+ dprintk("RPC: rpcb_decode_getport result %u\n",
|
|
*portp);
|
|
*portp);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -447,8 +657,8 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
|
|
unsigned int *boolp)
|
|
unsigned int *boolp)
|
|
{
|
|
{
|
|
*boolp = (unsigned int) ntohl(*p++);
|
|
*boolp = (unsigned int) ntohl(*p++);
|
|
- dprintk("RPC: rpcb_decode_set result %u\n",
|
|
|
|
- *boolp);
|
|
|
|
|
|
+ dprintk("RPC: rpcb_decode_set: call %s\n",
|
|
|
|
+ (*boolp ? "succeeded" : "failed"));
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -571,52 +781,60 @@ out_err:
|
|
static struct rpc_procinfo rpcb_procedures2[] = {
|
|
static struct rpc_procinfo rpcb_procedures2[] = {
|
|
PROC(SET, mapping, set),
|
|
PROC(SET, mapping, set),
|
|
PROC(UNSET, mapping, set),
|
|
PROC(UNSET, mapping, set),
|
|
- PROC(GETADDR, mapping, getport),
|
|
|
|
|
|
+ PROC(GETPORT, mapping, getport),
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpc_procinfo rpcb_procedures3[] = {
|
|
static struct rpc_procinfo rpcb_procedures3[] = {
|
|
- PROC(SET, mapping, set),
|
|
|
|
- PROC(UNSET, mapping, set),
|
|
|
|
|
|
+ PROC(SET, getaddr, set),
|
|
|
|
+ PROC(UNSET, getaddr, set),
|
|
PROC(GETADDR, getaddr, getaddr),
|
|
PROC(GETADDR, getaddr, getaddr),
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpc_procinfo rpcb_procedures4[] = {
|
|
static struct rpc_procinfo rpcb_procedures4[] = {
|
|
- PROC(SET, mapping, set),
|
|
|
|
- PROC(UNSET, mapping, set),
|
|
|
|
|
|
+ PROC(SET, getaddr, set),
|
|
|
|
+ PROC(UNSET, getaddr, set),
|
|
|
|
+ PROC(GETADDR, getaddr, getaddr),
|
|
PROC(GETVERSADDR, getaddr, getaddr),
|
|
PROC(GETVERSADDR, getaddr, getaddr),
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpcb_info rpcb_next_version[] = {
|
|
static struct rpcb_info rpcb_next_version[] = {
|
|
-#ifdef CONFIG_SUNRPC_BIND34
|
|
|
|
- { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
|
|
|
|
- { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
|
|
|
|
-#endif
|
|
|
|
- { 2, &rpcb_procedures2[RPCBPROC_GETPORT] },
|
|
|
|
- { 0, NULL },
|
|
|
|
|
|
+ {
|
|
|
|
+ .rpc_vers = RPCBVERS_2,
|
|
|
|
+ .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT],
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ .rpc_proc = NULL,
|
|
|
|
+ },
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpcb_info rpcb_next_version6[] = {
|
|
static struct rpcb_info rpcb_next_version6[] = {
|
|
-#ifdef CONFIG_SUNRPC_BIND34
|
|
|
|
- { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
|
|
|
|
- { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
|
|
|
|
-#endif
|
|
|
|
- { 0, NULL },
|
|
|
|
|
|
+ {
|
|
|
|
+ .rpc_vers = RPCBVERS_4,
|
|
|
|
+ .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR],
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ .rpc_vers = RPCBVERS_3,
|
|
|
|
+ .rpc_proc = &rpcb_procedures3[RPCBPROC_GETADDR],
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ .rpc_proc = NULL,
|
|
|
|
+ },
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpc_version rpcb_version2 = {
|
|
static struct rpc_version rpcb_version2 = {
|
|
- .number = 2,
|
|
|
|
|
|
+ .number = RPCBVERS_2,
|
|
.nrprocs = RPCB_HIGHPROC_2,
|
|
.nrprocs = RPCB_HIGHPROC_2,
|
|
.procs = rpcb_procedures2
|
|
.procs = rpcb_procedures2
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpc_version rpcb_version3 = {
|
|
static struct rpc_version rpcb_version3 = {
|
|
- .number = 3,
|
|
|
|
|
|
+ .number = RPCBVERS_3,
|
|
.nrprocs = RPCB_HIGHPROC_3,
|
|
.nrprocs = RPCB_HIGHPROC_3,
|
|
.procs = rpcb_procedures3
|
|
.procs = rpcb_procedures3
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpc_version rpcb_version4 = {
|
|
static struct rpc_version rpcb_version4 = {
|
|
- .number = 4,
|
|
|
|
|
|
+ .number = RPCBVERS_4,
|
|
.nrprocs = RPCB_HIGHPROC_4,
|
|
.nrprocs = RPCB_HIGHPROC_4,
|
|
.procs = rpcb_procedures4
|
|
.procs = rpcb_procedures4
|
|
};
|
|
};
|