Commit d5b64430 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust

SUNRPC: add support for IPv6 to the kernel's rpcbind client

Prepare for adding IPv6 support to the RPC client by adding IPv6
capabilities to rpcbind.  Note that this is support on the query side
only; registering IPv6 addresses with the local portmapper will come
later.

Note we have to take care not to fall back to using version 2 of the
rpcbind protocol if we're dealing with IPv6 address.  Version 2 doesn't
support IPv6 at all.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Cc: Aurelien Charbon <aurelien.charbon@ext.bull.net>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 4b6473fb
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -137,10 +139,13 @@ struct rpcbind_args { ...@@ -137,10 +139,13 @@ struct rpcbind_args {
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 rpcb_info { struct rpcb_info {
int rpc_vers; int rpc_vers;
struct rpc_procinfo * rpc_proc; struct rpc_procinfo * rpc_proc;
} rpcb_next_version[]; };
static struct rpcb_info rpcb_next_version[];
static struct rpcb_info rpcb_next_version6[];
static void rpcb_getport_prepare(struct rpc_task *task, void *calldata) static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
{ {
...@@ -190,7 +195,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, ...@@ -190,7 +195,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
RPC_CLNT_CREATE_INTR), RPC_CLNT_CREATE_INTR),
}; };
((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); switch (srvaddr->sa_family) {
case AF_INET:
((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
break;
case AF_INET6:
((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
break;
default:
return NULL;
}
if (!privileged) if (!privileged)
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
return rpc_create(&args); return rpc_create(&args);
...@@ -316,6 +331,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -316,6 +331,7 @@ void rpcb_getport_async(struct rpc_task *task)
struct rpc_task *child; struct rpc_task *child;
struct sockaddr addr; struct sockaddr addr;
int status; int status;
struct rpcb_info *info;
dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
task->tk_pid, __FUNCTION__, task->tk_pid, __FUNCTION__,
...@@ -343,14 +359,30 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -343,14 +359,30 @@ void rpcb_getport_async(struct rpc_task *task)
goto bailout_nofree; goto bailout_nofree;
} }
if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) { rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
/* Don't ever use rpcbind v2 for AF_INET6 requests */
switch (addr.sa_family) {
case AF_INET:
info = rpcb_next_version;
break;
case AF_INET6:
info = rpcb_next_version6;
break;
default:
status = -EAFNOSUPPORT;
dprintk("RPC: %5u %s: bad address family\n",
task->tk_pid, __FUNCTION__);
goto bailout_nofree;
}
if (info[xprt->bind_index].rpc_proc == NULL) {
xprt->bind_index = 0; xprt->bind_index = 0;
status = -EACCES; /* tell caller to try again later */ status = -EACCES; /* tell caller to try again later */
dprintk("RPC: %5u %s: no more getport versions available\n", dprintk("RPC: %5u %s: no more getport versions available\n",
task->tk_pid, __FUNCTION__); task->tk_pid, __FUNCTION__);
goto bailout_nofree; goto bailout_nofree;
} }
bind_version = rpcb_next_version[xprt->bind_index].rpc_vers; bind_version = info[xprt->bind_index].rpc_vers;
dprintk("RPC: %5u %s: trying rpcbind version %u\n", dprintk("RPC: %5u %s: trying rpcbind version %u\n",
task->tk_pid, __FUNCTION__, bind_version); task->tk_pid, __FUNCTION__, bind_version);
...@@ -373,7 +405,6 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -373,7 +405,6 @@ void rpcb_getport_async(struct rpc_task *task)
sizeof(map->r_addr)); sizeof(map->r_addr));
map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0); rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
if (IS_ERR(rpcb_clnt)) { if (IS_ERR(rpcb_clnt)) {
status = PTR_ERR(rpcb_clnt); status = PTR_ERR(rpcb_clnt);
...@@ -594,6 +625,14 @@ static struct rpcb_info rpcb_next_version[] = { ...@@ -594,6 +625,14 @@ static struct rpcb_info rpcb_next_version[] = {
{ 0, NULL }, { 0, NULL },
}; };
static struct rpcb_info rpcb_next_version6[] = {
#ifdef CONFIG_SUNRPC_BIND34
{ 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
{ 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
#endif
{ 0, NULL },
};
static struct rpc_version rpcb_version2 = { static struct rpc_version rpcb_version2 = {
.number = 2, .number = 2,
.nrprocs = RPCB_HIGHPROC_2, .nrprocs = RPCB_HIGHPROC_2,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment