diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 51 |
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 { | |||
137 | static struct rpc_procinfo rpcb_procedures2[]; | 139 | static struct rpc_procinfo rpcb_procedures2[]; |
138 | static struct rpc_procinfo rpcb_procedures3[]; | 140 | static struct rpc_procinfo rpcb_procedures3[]; |
139 | 141 | ||
140 | static struct rpcb_info { | 142 | struct 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 | |||
147 | static struct rpcb_info rpcb_next_version[]; | ||
148 | static struct rpcb_info rpcb_next_version6[]; | ||
144 | 149 | ||
145 | static void rpcb_getport_prepare(struct rpc_task *task, void *calldata) | 150 | static 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 | ||
628 | static 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 | |||
597 | static struct rpc_version rpcb_version2 = { | 636 | static struct rpc_version rpcb_version2 = { |
598 | .number = 2, | 637 | .number = 2, |
599 | .nrprocs = RPCB_HIGHPROC_2, | 638 | .nrprocs = RPCB_HIGHPROC_2, |