Currently the kernel RPC implements only the portmap (v2) to register/unregister
a program and to get the port of a program. Some implementations don't support
the portmap (replaced by the rpcbind) with new transports such as IPv6. So at
least the getaddr function of the rpcbind has to be supported.
Since there is no mean to know which version of the portmapper is available on
the remote machine, we have to try one and, if this fails with an mismatch version
error, retry the other one.

To limit the duplication of code, and to increase the maintainability, 
pmap_getport6() has been suppressed. pmap_getport() is called for both IPv4 and
IPv6 protocols but pmap_create() or pmap_create6() is called according to the
address family.

Signed-off-by: Gilles Quillard <Gilles.Quillard@bull.net>
Signed-off-by: Aurelien Charbon <Aurelien.Charbon@ext.bull.net>

---

 include/linux/sunrpc/xprt.h |    7 
 net/sunrpc/Makefile         |    2 
 net/sunrpc/clnt.c           |    7 
 net/sunrpc/pmap_clnt.c      |  106 ++------------
 net/sunrpc/rpcb_clnt.c      |  321 ++++++++++++++++++++++++++++++++++++++++++++
 net/sunrpc/xprtsock.c       |   19 ++
 6 files changed, 365 insertions(+), 97 deletions(-)

---

diff -Nru linux-2.6.11-05/include/linux/sunrpc/xprt.h linux-2.6.11-06/include/linux/sunrpc/xprt.h
--- linux-2.6.11-05/include/linux/sunrpc/xprt.h	2005-03-15 11:03:28.000000000 +0100
+++ linux-2.6.11-06/include/linux/sunrpc/xprt.h	2005-03-17 13:39:11.000000000 +0100
@@ -178,7 +178,8 @@
 	unsigned long		state;		/* transport state */
 	unsigned char		shutdown   : 1,	/* being shut down */
 				need_bind  : 1, /* force a rebind */
-				resvport   : 1; /* use a reserved port */
+				resvport   : 1, /* use a reserved port */
+				alt_getport : 1; /* use alternate getport */
 
 	/*
 	 * Connection of transports
@@ -234,11 +235,9 @@
  */
 int			pmap_register(u32, u32, int, unsigned short, int *);
 void			pmap_getport(struct rpc_task *, struct rpc_clnt *);
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-void			pmap_getport6(struct rpc_task *, struct rpc_clnt *);
-#endif
 int			pmap_getport_external(struct sockaddr_in *, u32,
 					u32, int);
+void			rpcb_getport(struct rpc_task *, struct rpc_clnt *);
 
 static inline size_t xprt_tsh_size(struct rpc_xprt *xprt)
 {
diff -Nru linux-2.6.11-05/net/sunrpc/clnt.c linux-2.6.11-06/net/sunrpc/clnt.c
--- linux-2.6.11-05/net/sunrpc/clnt.c	2005-03-14 14:51:31.000000000 +0100
+++ linux-2.6.11-06/net/sunrpc/clnt.c	2005-03-17 16:30:59.000000000 +0100
@@ -1203,6 +1203,13 @@
 				(unsigned int)task->tk_client->cl_prog,
 				(unsigned int)task->tk_client->cl_vers,
 				task->tk_client->cl_server);
+		/* If the portmapper doesn't support the specified version,
+	 	 * try an other one if any */
+		if (task->tk_xprt->alt_getport) {
+			dprintk("RPC %5u %s: try another version\n", task->tk_pid, __FUNCTION__);
+			task->tk_action = call_bind;
+			return NULL;
+		}
 		error = -ENOSYS;
 		goto out_err;
 	case RPC_PROC_UNAVAIL:
diff -Nru linux-2.6.11-05/net/sunrpc/Makefile linux-2.6.11-06/net/sunrpc/Makefile
--- linux-2.6.11-05/net/sunrpc/Makefile	2005-03-14 14:51:31.000000000 +0100
+++ linux-2.6.11-06/net/sunrpc/Makefile	2005-03-17 10:28:14.000000000 +0100
@@ -10,7 +10,7 @@
 sunrpc-y := clnt.o xprt.o socklib.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
 	    svc.o svcsock.o svcauth.o svcauth_unix.o \
-	    pmap_clnt.o timer.o xdr.o \
+	    pmap_clnt.o rpcb_clnt.o timer.o xdr.o \
 	    sunrpc_syms.o cache.o rpc_pipe.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
diff -Nru linux-2.6.11-05/net/sunrpc/pmap_clnt.c linux-2.6.11-06/net/sunrpc/pmap_clnt.c
--- linux-2.6.11-05/net/sunrpc/pmap_clnt.c	2005-03-14 14:51:31.000000000 +0100
+++ linux-2.6.11-06/net/sunrpc/pmap_clnt.c	2005-03-17 11:26:59.000000000 +0100
@@ -37,6 +37,7 @@
 	u32			pm_prot;
 	unsigned short		pm_port;
 	struct rpc_task *	pm_wake;
+	struct rpc_clnt *	pm_clnt;
 };
 
 static struct rpc_procinfo	pmap_procedures[];
@@ -63,13 +64,13 @@
 {
 	int protocol = rpc_aux_protocol(clnt);
 	struct rpc_xprt *xprt = task->tk_xprt;
-	struct sockaddr_in addr;
+	struct sockaddr_storage addr;
 	struct rpc_message msg = {
 		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
 		.rpc_cred	= NULL
 	};
 	struct portmap_args *map;
-	struct rpc_clnt	*pmap_clnt;
+	struct rpc_clnt	*pmap_clnt = NULL;
 	struct rpc_task	*child;
 
 	dprintk("RPC: %5u pmap_getport(%s, %u, %u, %d)\n",
@@ -98,87 +99,28 @@
 	map->pm_port = 0;
 	map->pm_wake = task;
 
-	rpc_peeraddr(clnt, &addr, sizeof(addr));
-	pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot);
-	if (IS_ERR(pmap_clnt)) {
-		rpc_exit(task, PTR_ERR(pmap_clnt));
-		goto bailout;
-	}
-
-	/* NB: rpc_new_child will release client after a failure. */
-	if (!(child = rpc_new_child(pmap_clnt, task))) {
-		rpc_exit(task, -EIO);
-		goto bailout;
-	}
-
-	/* Setup the call info struct */
-	msg.rpc_argp = map;
-	msg.rpc_resp = &map->pm_port;
-	rpc_call_setup(child, &msg, 0);
-	if (child->tk_status != 0) {
-		rpc_exit(task, child->tk_status);
-		goto bailout;
-	}
-
-	/* ... and run the child task */
-	child->tk_calldata = map;
-	child->tk_exit = pmap_getport_done;
-	rpc_run_child(task, child);
-	return;
-
-bailout:
-	kfree(map);
-bailout_nofree:
-	pmap_wake_portmap_waiters(xprt);
-}
-EXPORT_SYMBOL_GPL(pmap_getport);
-
+	rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+	if (addr.ss_family == AF_INET) {
+		pmap_clnt = pmap_create(clnt->cl_server,
+					(struct sockaddr_in *)&addr,
+					map->pm_prot);
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-void pmap_getport6(struct rpc_task *task, struct rpc_clnt *clnt)
-{
-	int protocol = rpc_aux_protocol(clnt);
-	struct rpc_xprt *xprt = task->tk_xprt;
-	struct sockaddr_in6 addr;
-	struct rpc_message msg = {
-		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
-		.rpc_cred	= NULL
-	};
-	struct portmap_args *map;
-	struct rpc_clnt	*pmap_clnt;
-	struct rpc_task	*child;
-
-	dprintk("RPC: %5u pmap_getport6(%s, %u, %u, %d)\n",
+	} else if (addr.ss_family == AF_INET6) {
+		pmap_clnt = pmap_create6(clnt->cl_server,
+					 (struct sockaddr_in6 *)&addr,
+					 map->pm_prot);
+#endif
+	} else {
+		dprintk("RPC: %5u pmap_getport(%s, %u, %u, %d) address family not supported.\n",
 			task->tk_pid, clnt->cl_server,
 			clnt->cl_prog, clnt->cl_vers, protocol);
-
-	if (test_and_set_bit(XPRT_BINDING, &xprt->state)) {
-		rpc_sleep_on(&xprt->bindwait, task, NULL, NULL);
-		return;
-	}
-
-	/* Someone else may have bound if we slept */
-	if (xprt_is_bound(xprt)) {
-		rpc_exit(task, 0);
-		goto bailout_nofree;
+		rpc_exit(task, -EBADF);
 	}
-
-	map = kmalloc(sizeof(struct portmap_args), GFP_NOFS);
-	if (!map) {
-		rpc_exit(task, -ENOMEM);
-		goto bailout_nofree;
-	}
-	map->pm_prog = clnt->cl_prog;
-	map->pm_vers = clnt->cl_vers;
-	map->pm_prot = protocol;
-	map->pm_port = 0;
-	map->pm_wake = task;
-
-	rpc_peeraddr(clnt, &addr, sizeof(addr));
-	pmap_clnt = pmap_create6(clnt->cl_server, &addr, map->pm_prot);
 	if (IS_ERR(pmap_clnt)) {
 		rpc_exit(task, PTR_ERR(pmap_clnt));
 		goto bailout;
 	}
+	map->pm_clnt = pmap_clnt;
 
 	/* NB: rpc_new_child will release client after a failure. */
 	if (!(child = rpc_new_child(pmap_clnt, task))) {
@@ -206,19 +148,7 @@
 bailout_nofree:
 	pmap_wake_portmap_waiters(xprt);
 }
-#else
-void pmap_getport6(struct rpc_task *task, struct rpc_clnt *clnt)
-{
-	int protocol = rpc_aux_protocol(clnt);
-
-	dprintk("RPC: %5u pmap_getport6(%s, %u, %u, %d) not supported.\n",
-			task->tk_pid, clnt->cl_server,
-			clnt->cl_prog, clnt->cl_vers, protocol);
-
-	rpc_exit(task, -EBADF);
-}
-#endif
-EXPORT_SYMBOL_GPL(pmap_getport6);
+EXPORT_SYMBOL_GPL(pmap_getport);
 
 #ifdef CONFIG_ROOT_NFS
 int pmap_getport_external(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
diff -Nru linux-2.6.11-05/net/sunrpc/rpcb_clnt.c linux-2.6.11-06/net/sunrpc/rpcb_clnt.c
--- linux-2.6.11-05/net/sunrpc/rpcb_clnt.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-06/net/sunrpc/rpcb_clnt.c	2005-03-17 15:54:42.000000000 +0100
@@ -0,0 +1,321 @@
+/*
+ * linux/net/sunrpc/rpcb_clnt.c
+ *
+ * Rpcbind client.
+ *
+ * Rpcbind supports versions 3 and 4 of the rpcbind protocol (RFC 1833).
+ *
+ * Added by Gilles Quillard, Bull Open Source, 2005 <gilles.quillard@bull.net>
+ * Only getaddr function of rpcbind version 3 is currently impelmented.
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/sched.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY	RPCDBG_PMAP
+#endif
+
+#define RPCB_SET		1
+#define RPCB_UNSET		2
+#define RPCB_GETADDR		3
+
+#define RPC_RPCB_VERSION	3
+
+static struct rpc_procinfo	rpcb_procedures[];
+static struct rpc_clnt *	rpcb_create(char *, struct sockaddr_in *, int);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static struct rpc_clnt *	rpcb_create6(char *, struct sockaddr_in6 *, int);
+#endif
+static void			rpcb_getport_done(struct rpc_task *);
+extern struct rpc_program	rpcb_program;
+
+struct rpcbind_args {
+	u32 			r_prog;
+	u32 			r_vers;
+	unsigned short		r_port;
+	char 			r_addr[40];
+	struct rpc_task *       r_wake;
+};
+
+static inline void rpcb_wake_up_rpcbind_waiters(struct rpc_xprt *xprt)
+{
+	smp_mb__before_clear_bit();
+	clear_bit(XPRT_BINDING, &xprt->state);
+	smp_mb__after_clear_bit();
+	rpc_wake_up(&xprt->bindwait);
+}
+
+void rpcb_getport(struct rpc_task *task, struct rpc_clnt *clnt)
+{
+	int protocol = rpc_aux_protocol(clnt);
+	struct rpc_xprt *xprt = task->tk_xprt;
+	struct sockaddr_storage addr;
+	struct rpc_message msg = {
+		.rpc_proc	= &rpcb_procedures[RPCB_GETADDR],
+		.rpc_cred	= NULL
+	};
+	static struct rpcbind_args *map;
+	struct rpc_clnt	*rpcb_clnt = NULL;
+	struct rpc_task	*child;
+
+	dprintk("RPC: %5u rpcb_getport(%s, %u, %u, %d)\n",
+			task->tk_pid, clnt->cl_server,
+			clnt->cl_prog, clnt->cl_vers, protocol);
+
+	if (test_and_set_bit(XPRT_BINDING, &xprt->state)) {
+		rpc_sleep_on(&xprt->bindwait, task, NULL, NULL);
+		return;
+	}
+
+	/* Someone else may have bound if we slept */
+	if (xprt_is_bound(xprt)) {
+		rpc_exit(task, 0);
+		goto bailout_nofree;
+	}
+
+	map = kmalloc(sizeof(struct rpcbind_args), GFP_NOFS);
+	if (!map) {
+		rpc_exit(task, -ENOMEM);
+		goto bailout_nofree;
+	}
+	map->r_prog = clnt->cl_prog;
+	map->r_vers = clnt->cl_vers;
+	map->r_port = 0;
+	map->r_wake = task;
+
+	rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+	rpc_print_peeraddr(clnt, (void *)map->r_addr, strlen(map->r_addr), 0x1);
+
+	if (addr.ss_family == AF_INET) {
+		rpcb_clnt = rpcb_create(clnt->cl_server,
+					(struct sockaddr_in *)&addr,
+					protocol);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+	}  else if (addr.ss_family == AF_INET6) {
+		rpcb_clnt = rpcb_create6(clnt->cl_server,
+					 (struct sockaddr_in6 *)&addr,
+					 protocol);
+#endif
+	} else {
+		dprintk("RPC: %5u rpcb_getport(%s, %u, %u, %d) address family not supported.\n",
+			task->tk_pid, clnt->cl_server,
+			clnt->cl_prog, clnt->cl_vers, protocol);
+		rpc_exit(task, -EBADF);
+	}
+
+	if (IS_ERR(rpcb_clnt)) {
+		task->tk_status = PTR_ERR(rpcb_clnt);
+		goto bailout;
+	}
+
+	/*
+	 * Note: rpc_new_child will release client after a failure.
+	 */
+	if (!(child = rpc_new_child(rpcb_clnt, task))) {
+		rpc_exit(task, -EIO);
+		goto bailout;
+	}
+
+	/* Setup the call info struct */
+	msg.rpc_argp = map;
+	msg.rpc_resp = &map->r_port;
+	rpc_call_setup(child, &msg, 0);
+	if (child->tk_status != 0) {
+		rpc_exit(task, child->tk_status);
+		goto bailout;
+	}
+
+	/* ... and run the child task */
+	child->tk_calldata = map;
+	child->tk_exit = rpcb_getport_done;
+	rpc_run_child(task, child);
+	return;
+
+bailout:
+	kfree(map);
+bailout_nofree:
+	rpcb_wake_up_rpcbind_waiters(xprt);
+}
+EXPORT_SYMBOL(rpcb_getport);
+
+/*
+ * Portmapper child task calls this callback via tk_exit.  This function is then
+ * responsible for waking the parent via rpc_child_exit.
+ */
+
+static void
+rpcb_getport_done(struct rpc_task *child)
+{
+	struct rpcbind_args *map = (struct rpcbind_args *) child->tk_calldata;
+	struct rpc_xprt *xprt = map->r_wake->tk_xprt;
+
+	if (child->tk_status < 0) {
+		/* Make the calling task exit with an error */
+		child->tk_action = NULL;
+	} else if (map->r_port == 0) {
+		/* Program not registered */
+		child->tk_status = -EACCES;
+		child->tk_action = NULL;
+	} else {
+		xprt->ops->set_port(xprt, map->r_port);
+		xprt->need_bind = 0;
+	}
+
+	dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
+			child->tk_pid, child->tk_status, map->r_port);
+
+	xprt->ops->set_port(xprt, map->r_port);
+	rpcb_wake_up_rpcbind_waiters(xprt);
+	rpc_child_exit(map->r_wake, child);
+	kfree(map);
+}
+
+static struct rpc_clnt * rpcb_create(char *hostname, struct sockaddr_in *srvaddr, int proto)
+{
+	struct rpc_create_args args = {
+		.protocol	= proto,
+		.address	= (struct sockaddr *)srvaddr,
+		.addrsize	= sizeof(*srvaddr),
+		.servername	= hostname,
+		.program	= &rpcb_program,
+		.version	= RPC_RPCB_VERSION,
+		.authflavor	= RPC_AUTH_NULL,
+		.behavior	= RPC_CLNT_SOFTRTRY | RPC_CLNT_CHATTY |
+					RPC_CLNT_ONESHOT,
+	};
+
+	srvaddr->sin_port = htons(RPC_PMAP_PORT);
+	return rpc_create(&args);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static struct rpc_clnt * rpcb_create6(char *hostname, struct sockaddr_in6 *srvaddr, int proto)
+{
+	struct rpc_create_args args = {
+		.protocol	= proto,
+		.address	= (struct sockaddr *)srvaddr,
+		.addrsize	= sizeof(*srvaddr),
+		.servername	= hostname,
+		.program	= &rpcb_program,
+		.version	= RPC_RPCB_VERSION,
+		.authflavor	= RPC_AUTH_NULL,
+		.behavior	= RPC_CLNT_SOFTRTRY | RPC_CLNT_CHATTY |
+					RPC_CLNT_ONESHOT,
+	};
+
+	srvaddr->sin6_port = htons(RPC_PMAP_PORT);
+	return rpc_create(&args);
+}
+#endif
+
+/*
+ * XDR encode/decode functions for RPCBIND
+ */
+static void
+xdr_addr_len_value(u32 **p, char *val)
+{
+	int len, offset;
+	len = strlen(val);
+	**p = htonl(len);
+	*p += 1;
+	strcpy((char *)*p, val);
+	offset = len / 4;
+	if (len % 4)
+		offset++;
+	*p += offset;
+}
+
+static int
+xdr_encode_getaddr(struct rpc_rqst *req, u32 *p, struct rpcbind_args *rpcb)
+{
+	char netid[] = "tcp";
+	char owner[] = "rpcb";
+
+	dprintk("RPC:       xdr_encode_getaddr(%u, %u, %s)\n",
+		rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
+	*p++ = htonl(rpcb->r_prog);
+	*p++ = htonl(rpcb->r_vers);
+	xdr_addr_len_value(&p, netid);
+	xdr_addr_len_value(&p, rpcb->r_addr);
+	xdr_addr_len_value(&p, owner);
+
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
+{
+	char *addr;
+	int addr_len, c, i, f, first, val;
+
+	*portp = 0;
+	addr_len = (unsigned int) ntohl(*p++);
+	addr = (char *)p;
+	val = 0;
+	first = 1;
+	f = 1;
+	for (i = addr_len - 1; i > 0; i--) {
+		c = addr[i];
+		if (c >= '0' && c <= '9') {
+			val += (c - '0') * f;
+			f *= 10;
+		} else if (c == '.') {
+			if (first) {
+				*portp = val;
+				val = first = 0;
+				f = 1;
+			} else {
+			         *portp |= (val << 8);
+				 break;
+			}
+		}
+	}
+	return 0;
+}
+
+static struct rpc_procinfo	rpcb_procedures[] = {
+[RPCB_GETADDR] = {
+	  .p_proc		= RPCB_GETADDR,
+	  .p_encode		= (kxdrproc_t) xdr_encode_getaddr,
+	  .p_decode		= (kxdrproc_t) xdr_decode_port,
+	  .p_bufsiz		= 4,
+	  .p_count		= 1,
+	},
+};
+
+static struct rpc_version	rpcb_version3 = {
+	.number		= 3,
+	.nrprocs	= 4,
+	.procs		= rpcb_procedures
+};
+
+static struct rpc_version *	rpcb_version[] = {
+	NULL,
+	NULL,
+	NULL,
+	&rpcb_version3
+};
+
+static struct rpc_stat		rpcb_stats;
+
+struct rpc_program	rpcb_program = {
+	.name		= "rpcbind",
+	.number		= RPC_PMAP_PROGRAM,
+	.nrvers		= ARRAY_SIZE(rpcb_version),
+	.version	= rpcb_version,
+	.stats		= &rpcb_stats,
+};
diff -Nru linux-2.6.11-05/net/sunrpc/xprtsock.c linux-2.6.11-06/net/sunrpc/xprtsock.c
--- linux-2.6.11-05/net/sunrpc/xprtsock.c	2005-03-15 11:03:27.000000000 +0100
+++ linux-2.6.11-06/net/sunrpc/xprtsock.c	2005-03-17 15:16:38.000000000 +0100
@@ -1753,11 +1753,22 @@
 	}
 }
 
+static void xs_getport(struct rpc_task *task, struct rpc_clnt *clnt)
+{
+	if (task->tk_xprt->alt_getport == 0) {
+		task->tk_xprt->alt_getport = 1;
+		rpcb_getport(task, clnt);
+	} else {
+		task->tk_xprt->alt_getport = 0;
+		pmap_getport(task, clnt);
+	}
+}
+
 static struct rpc_xprt_ops xs_udp_ops = {
 	.setbufsize	= xs_udp_setbufsize,
 	.print_addr	= xs_print_udp_ipv4_address,
 	.is_bound	= xs_is_bound,
-	.rpcbind	= pmap_getport,
+	.rpcbind	= xs_getport,
 	.set_port	= xs_set_port,
 	.connect	= xs_connect,
 	.aux_protocol	= xs_udp_aux_protocol,
@@ -1775,7 +1786,7 @@
 	.setbufsize	= xs_tcp_setbufsize,
 	.print_addr	= xs_print_tcp_ipv4_address,
 	.is_bound	= xs_is_bound,
-	.rpcbind	= pmap_getport,
+	.rpcbind	= xs_getport,
 	.set_port	= xs_set_port,
 	.connect	= xs_connect,
 	.aux_protocol	= xs_tcp_aux_protocol,
@@ -1794,7 +1805,7 @@
 	.setbufsize	= xs_udp_setbufsize,
 	.print_addr	= xs_print_udp_ipv6_address,
 	.is_bound	= xs_is_bound6,
-	.rpcbind	= pmap_getport6,
+	.rpcbind	= xs_getport,
 	.set_port	= xs_set_port6,
 	.connect	= xs_connect,
 	.aux_protocol	= xs_udp_aux_protocol,
@@ -1812,7 +1823,7 @@
 	.setbufsize	= xs_tcp_setbufsize,
 	.print_addr	= xs_print_tcp_ipv6_address,
 	.is_bound	= xs_is_bound6,
-	.rpcbind	= pmap_getport6,
+	.rpcbind	= xs_getport,
 	.set_port	= xs_set_port6,
 	.connect	= xs_connect,
 	.aux_protocol	= xs_tcp_aux_protocol,
