aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/rpcb_clnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r--net/sunrpc/rpcb_clnt.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index a9d2cdc8e32c..7db75e177e67 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -16,6 +16,8 @@
16 16
17#include <linux/types.h> 17#include <linux/types.h>
18#include <linux/socket.h> 18#include <linux/socket.h>
19#include <linux/in.h>
20#include <linux/in6.h>
19#include <linux/kernel.h> 21#include <linux/kernel.h>
20#include <linux/errno.h> 22#include <linux/errno.h>
21 23
@@ -137,10 +139,13 @@ struct rpcbind_args {
137static struct rpc_procinfo rpcb_procedures2[]; 139static struct rpc_procinfo rpcb_procedures2[];
138static struct rpc_procinfo rpcb_procedures3[]; 140static struct rpc_procinfo rpcb_procedures3[];
139 141
140static struct rpcb_info { 142struct rpcb_info {
141 int rpc_vers; 143 int rpc_vers;
142 struct rpc_procinfo * rpc_proc; 144 struct rpc_procinfo * rpc_proc;
143} rpcb_next_version[]; 145};
146
147static struct rpcb_info rpcb_next_version[];
148static struct rpcb_info rpcb_next_version6[];
144 149
145static void rpcb_getport_prepare(struct rpc_task *task, void *calldata) 150static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
146{ 151{
@@ -190,7 +195,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
190 RPC_CLNT_CREATE_INTR), 195 RPC_CLNT_CREATE_INTR),
191 }; 196 };
192 197
193 ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); 198 switch (srvaddr->sa_family) {
199 case AF_INET:
200 ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
201 break;
202 case AF_INET6:
203 ((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
204 break;
205 default:
206 return NULL;
207 }
208
194 if (!privileged) 209 if (!privileged)
195 args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; 210 args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
196 return rpc_create(&args); 211 return rpc_create(&args);
@@ -316,6 +331,7 @@ void rpcb_getport_async(struct rpc_task *task)
316 struct rpc_task *child; 331 struct rpc_task *child;
317 struct sockaddr addr; 332 struct sockaddr addr;
318 int status; 333 int status;
334 struct rpcb_info *info;
319 335
320 dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", 336 dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
321 task->tk_pid, __FUNCTION__, 337 task->tk_pid, __FUNCTION__,
@@ -343,14 +359,30 @@ void rpcb_getport_async(struct rpc_task *task)
343 goto bailout_nofree; 359 goto bailout_nofree;
344 } 360 }
345 361
346 if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) { 362 rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
363
364 /* Don't ever use rpcbind v2 for AF_INET6 requests */
365 switch (addr.sa_family) {
366 case AF_INET:
367 info = rpcb_next_version;
368 break;
369 case AF_INET6:
370 info = rpcb_next_version6;
371 break;
372 default:
373 status = -EAFNOSUPPORT;
374 dprintk("RPC: %5u %s: bad address family\n",
375 task->tk_pid, __FUNCTION__);
376 goto bailout_nofree;
377 }
378 if (info[xprt->bind_index].rpc_proc == NULL) {
347 xprt->bind_index = 0; 379 xprt->bind_index = 0;
348 status = -EACCES; /* tell caller to try again later */ 380 status = -EACCES; /* tell caller to try again later */
349 dprintk("RPC: %5u %s: no more getport versions available\n", 381 dprintk("RPC: %5u %s: no more getport versions available\n",
350 task->tk_pid, __FUNCTION__); 382 task->tk_pid, __FUNCTION__);
351 goto bailout_nofree; 383 goto bailout_nofree;
352 } 384 }
353 bind_version = rpcb_next_version[xprt->bind_index].rpc_vers; 385 bind_version = info[xprt->bind_index].rpc_vers;
354 386
355 dprintk("RPC: %5u %s: trying rpcbind version %u\n", 387 dprintk("RPC: %5u %s: trying rpcbind version %u\n",
356 task->tk_pid, __FUNCTION__, bind_version); 388 task->tk_pid, __FUNCTION__, bind_version);
@@ -373,7 +405,6 @@ void rpcb_getport_async(struct rpc_task *task)
373 sizeof(map->r_addr)); 405 sizeof(map->r_addr));
374 map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ 406 map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
375 407
376 rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
377 rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0); 408 rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
378 if (IS_ERR(rpcb_clnt)) { 409 if (IS_ERR(rpcb_clnt)) {
379 status = PTR_ERR(rpcb_clnt); 410 status = PTR_ERR(rpcb_clnt);
@@ -594,6 +625,14 @@ static struct rpcb_info rpcb_next_version[] = {
594 { 0, NULL }, 625 { 0, NULL },
595}; 626};
596 627
628static struct rpcb_info rpcb_next_version6[] = {
629#ifdef CONFIG_SUNRPC_BIND34
630 { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
631 { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
632#endif
633 { 0, NULL },
634};
635
597static struct rpc_version rpcb_version2 = { 636static struct rpc_version rpcb_version2 = {
598 .number = 2, 637 .number = 2,
599 .nrprocs = RPCB_HIGHPROC_2, 638 .nrprocs = RPCB_HIGHPROC_2,