18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * In-kernel rpcbind client supporting versions 2, 3, and 4 of the rpcbind
48c2ecf20Sopenharmony_ci * protocol
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Based on RFC 1833: "Binding Protocols for ONC RPC Version 2" and
78c2ecf20Sopenharmony_ci * RFC 3530: "Network File System (NFS) version 4 Protocol"
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Original: Gilles Quillard, Bull Open Source, 2005 <gilles.quillard@bull.net>
108c2ecf20Sopenharmony_ci * Updated: Chuck Lever, Oracle Corporation, 2007 <chuck.lever@oracle.com>
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Descended from net/sunrpc/pmap_clnt.c,
138c2ecf20Sopenharmony_ci *  Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/types.h>
198c2ecf20Sopenharmony_ci#include <linux/socket.h>
208c2ecf20Sopenharmony_ci#include <linux/un.h>
218c2ecf20Sopenharmony_ci#include <linux/in.h>
228c2ecf20Sopenharmony_ci#include <linux/in6.h>
238c2ecf20Sopenharmony_ci#include <linux/kernel.h>
248c2ecf20Sopenharmony_ci#include <linux/errno.h>
258c2ecf20Sopenharmony_ci#include <linux/mutex.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci#include <net/ipv6.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h>
308c2ecf20Sopenharmony_ci#include <linux/sunrpc/addr.h>
318c2ecf20Sopenharmony_ci#include <linux/sunrpc/sched.h>
328c2ecf20Sopenharmony_ci#include <linux/sunrpc/xprtsock.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <trace/events/sunrpc.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include "netns.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define RPCBIND_SOCK_PATHNAME	"/var/run/rpcbind.sock"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define RPCBIND_PROGRAM		(100000u)
418c2ecf20Sopenharmony_ci#define RPCBIND_PORT		(111u)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define RPCBVERS_2		(2u)
448c2ecf20Sopenharmony_ci#define RPCBVERS_3		(3u)
458c2ecf20Sopenharmony_ci#define RPCBVERS_4		(4u)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cienum {
488c2ecf20Sopenharmony_ci	RPCBPROC_NULL,
498c2ecf20Sopenharmony_ci	RPCBPROC_SET,
508c2ecf20Sopenharmony_ci	RPCBPROC_UNSET,
518c2ecf20Sopenharmony_ci	RPCBPROC_GETPORT,
528c2ecf20Sopenharmony_ci	RPCBPROC_GETADDR = 3,		/* alias for GETPORT */
538c2ecf20Sopenharmony_ci	RPCBPROC_DUMP,
548c2ecf20Sopenharmony_ci	RPCBPROC_CALLIT,
558c2ecf20Sopenharmony_ci	RPCBPROC_BCAST = 5,		/* alias for CALLIT */
568c2ecf20Sopenharmony_ci	RPCBPROC_GETTIME,
578c2ecf20Sopenharmony_ci	RPCBPROC_UADDR2TADDR,
588c2ecf20Sopenharmony_ci	RPCBPROC_TADDR2UADDR,
598c2ecf20Sopenharmony_ci	RPCBPROC_GETVERSADDR,
608c2ecf20Sopenharmony_ci	RPCBPROC_INDIRECT,
618c2ecf20Sopenharmony_ci	RPCBPROC_GETADDRLIST,
628c2ecf20Sopenharmony_ci	RPCBPROC_GETSTAT,
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/*
668c2ecf20Sopenharmony_ci * r_owner
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * The "owner" is allowed to unset a service in the rpcbind database.
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci * For AF_LOCAL SET/UNSET requests, rpcbind treats this string as a
718c2ecf20Sopenharmony_ci * UID which it maps to a local user name via a password lookup.
728c2ecf20Sopenharmony_ci * In all other cases it is ignored.
738c2ecf20Sopenharmony_ci *
748c2ecf20Sopenharmony_ci * For SET/UNSET requests, user space provides a value, even for
758c2ecf20Sopenharmony_ci * network requests, and GETADDR uses an empty string.  We follow
768c2ecf20Sopenharmony_ci * those precedents here.
778c2ecf20Sopenharmony_ci */
788c2ecf20Sopenharmony_ci#define RPCB_OWNER_STRING	"0"
798c2ecf20Sopenharmony_ci#define RPCB_MAXOWNERLEN	sizeof(RPCB_OWNER_STRING)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*
828c2ecf20Sopenharmony_ci * XDR data type sizes
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_ci#define RPCB_program_sz		(1)
858c2ecf20Sopenharmony_ci#define RPCB_version_sz		(1)
868c2ecf20Sopenharmony_ci#define RPCB_protocol_sz	(1)
878c2ecf20Sopenharmony_ci#define RPCB_port_sz		(1)
888c2ecf20Sopenharmony_ci#define RPCB_boolean_sz		(1)
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define RPCB_netid_sz		(1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
918c2ecf20Sopenharmony_ci#define RPCB_addr_sz		(1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
928c2ecf20Sopenharmony_ci#define RPCB_ownerstring_sz	(1 + XDR_QUADLEN(RPCB_MAXOWNERLEN))
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/*
958c2ecf20Sopenharmony_ci * XDR argument and result sizes
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_ci#define RPCB_mappingargs_sz	(RPCB_program_sz + RPCB_version_sz + \
988c2ecf20Sopenharmony_ci				RPCB_protocol_sz + RPCB_port_sz)
998c2ecf20Sopenharmony_ci#define RPCB_getaddrargs_sz	(RPCB_program_sz + RPCB_version_sz + \
1008c2ecf20Sopenharmony_ci				RPCB_netid_sz + RPCB_addr_sz + \
1018c2ecf20Sopenharmony_ci				RPCB_ownerstring_sz)
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define RPCB_getportres_sz	RPCB_port_sz
1048c2ecf20Sopenharmony_ci#define RPCB_setres_sz		RPCB_boolean_sz
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/*
1078c2ecf20Sopenharmony_ci * Note that RFC 1833 does not put any size restrictions on the
1088c2ecf20Sopenharmony_ci * address string returned by the remote rpcbind database.
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_ci#define RPCB_getaddrres_sz	RPCB_addr_sz
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic void			rpcb_getport_done(struct rpc_task *, void *);
1138c2ecf20Sopenharmony_cistatic void			rpcb_map_release(void *data);
1148c2ecf20Sopenharmony_cistatic const struct rpc_program	rpcb_program;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistruct rpcbind_args {
1178c2ecf20Sopenharmony_ci	struct rpc_xprt *	r_xprt;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	u32			r_prog;
1208c2ecf20Sopenharmony_ci	u32			r_vers;
1218c2ecf20Sopenharmony_ci	u32			r_prot;
1228c2ecf20Sopenharmony_ci	unsigned short		r_port;
1238c2ecf20Sopenharmony_ci	const char *		r_netid;
1248c2ecf20Sopenharmony_ci	const char *		r_addr;
1258c2ecf20Sopenharmony_ci	const char *		r_owner;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	int			r_status;
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic const struct rpc_procinfo rpcb_procedures2[];
1318c2ecf20Sopenharmony_cistatic const struct rpc_procinfo rpcb_procedures3[];
1328c2ecf20Sopenharmony_cistatic const struct rpc_procinfo rpcb_procedures4[];
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistruct rpcb_info {
1358c2ecf20Sopenharmony_ci	u32			rpc_vers;
1368c2ecf20Sopenharmony_ci	const struct rpc_procinfo *rpc_proc;
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic const struct rpcb_info rpcb_next_version[];
1408c2ecf20Sopenharmony_cistatic const struct rpcb_info rpcb_next_version6[];
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic const struct rpc_call_ops rpcb_getport_ops = {
1438c2ecf20Sopenharmony_ci	.rpc_call_done		= rpcb_getport_done,
1448c2ecf20Sopenharmony_ci	.rpc_release		= rpcb_map_release,
1458c2ecf20Sopenharmony_ci};
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	xprt_clear_binding(xprt);
1508c2ecf20Sopenharmony_ci	rpc_wake_up_status(&xprt->binding, status);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic void rpcb_map_release(void *data)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct rpcbind_args *map = data;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status);
1588c2ecf20Sopenharmony_ci	xprt_put(map->r_xprt);
1598c2ecf20Sopenharmony_ci	kfree(map->r_addr);
1608c2ecf20Sopenharmony_ci	kfree(map);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int rpcb_get_local(struct net *net)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	int cnt;
1668c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	spin_lock(&sn->rpcb_clnt_lock);
1698c2ecf20Sopenharmony_ci	if (sn->rpcb_users)
1708c2ecf20Sopenharmony_ci		sn->rpcb_users++;
1718c2ecf20Sopenharmony_ci	cnt = sn->rpcb_users;
1728c2ecf20Sopenharmony_ci	spin_unlock(&sn->rpcb_clnt_lock);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return cnt;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_civoid rpcb_put_local(struct net *net)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1808c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt = sn->rpcb_local_clnt;
1818c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4;
1828c2ecf20Sopenharmony_ci	int shutdown = 0;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	spin_lock(&sn->rpcb_clnt_lock);
1858c2ecf20Sopenharmony_ci	if (sn->rpcb_users) {
1868c2ecf20Sopenharmony_ci		if (--sn->rpcb_users == 0) {
1878c2ecf20Sopenharmony_ci			sn->rpcb_local_clnt = NULL;
1888c2ecf20Sopenharmony_ci			sn->rpcb_local_clnt4 = NULL;
1898c2ecf20Sopenharmony_ci		}
1908c2ecf20Sopenharmony_ci		shutdown = !sn->rpcb_users;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci	spin_unlock(&sn->rpcb_clnt_lock);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (shutdown) {
1958c2ecf20Sopenharmony_ci		/*
1968c2ecf20Sopenharmony_ci		 * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
1978c2ecf20Sopenharmony_ci		 */
1988c2ecf20Sopenharmony_ci		if (clnt4)
1998c2ecf20Sopenharmony_ci			rpc_shutdown_client(clnt4);
2008c2ecf20Sopenharmony_ci		if (clnt)
2018c2ecf20Sopenharmony_ci			rpc_shutdown_client(clnt);
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic void rpcb_set_local(struct net *net, struct rpc_clnt *clnt,
2068c2ecf20Sopenharmony_ci			struct rpc_clnt *clnt4,
2078c2ecf20Sopenharmony_ci			bool is_af_local)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* Protected by rpcb_create_local_mutex */
2128c2ecf20Sopenharmony_ci	sn->rpcb_local_clnt = clnt;
2138c2ecf20Sopenharmony_ci	sn->rpcb_local_clnt4 = clnt4;
2148c2ecf20Sopenharmony_ci	sn->rpcb_is_af_local = is_af_local ? 1 : 0;
2158c2ecf20Sopenharmony_ci	smp_wmb();
2168c2ecf20Sopenharmony_ci	sn->rpcb_users = 1;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/*
2208c2ecf20Sopenharmony_ci * Returns zero on success, otherwise a negative errno value
2218c2ecf20Sopenharmony_ci * is returned.
2228c2ecf20Sopenharmony_ci */
2238c2ecf20Sopenharmony_cistatic int rpcb_create_local_unix(struct net *net)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	static const struct sockaddr_un rpcb_localaddr_rpcbind = {
2268c2ecf20Sopenharmony_ci		.sun_family		= AF_LOCAL,
2278c2ecf20Sopenharmony_ci		.sun_path		= RPCBIND_SOCK_PATHNAME,
2288c2ecf20Sopenharmony_ci	};
2298c2ecf20Sopenharmony_ci	struct rpc_create_args args = {
2308c2ecf20Sopenharmony_ci		.net		= net,
2318c2ecf20Sopenharmony_ci		.protocol	= XPRT_TRANSPORT_LOCAL,
2328c2ecf20Sopenharmony_ci		.address	= (struct sockaddr *)&rpcb_localaddr_rpcbind,
2338c2ecf20Sopenharmony_ci		.addrsize	= sizeof(rpcb_localaddr_rpcbind),
2348c2ecf20Sopenharmony_ci		.servername	= "localhost",
2358c2ecf20Sopenharmony_ci		.program	= &rpcb_program,
2368c2ecf20Sopenharmony_ci		.version	= RPCBVERS_2,
2378c2ecf20Sopenharmony_ci		.authflavor	= RPC_AUTH_NULL,
2388c2ecf20Sopenharmony_ci		.cred		= current_cred(),
2398c2ecf20Sopenharmony_ci		/*
2408c2ecf20Sopenharmony_ci		 * We turn off the idle timeout to prevent the kernel
2418c2ecf20Sopenharmony_ci		 * from automatically disconnecting the socket.
2428c2ecf20Sopenharmony_ci		 * Otherwise, we'd have to cache the mount namespace
2438c2ecf20Sopenharmony_ci		 * of the caller and somehow pass that to the socket
2448c2ecf20Sopenharmony_ci		 * reconnect code.
2458c2ecf20Sopenharmony_ci		 */
2468c2ecf20Sopenharmony_ci		.flags		= RPC_CLNT_CREATE_NO_IDLE_TIMEOUT,
2478c2ecf20Sopenharmony_ci	};
2488c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt, *clnt4;
2498c2ecf20Sopenharmony_ci	int result = 0;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/*
2528c2ecf20Sopenharmony_ci	 * Because we requested an RPC PING at transport creation time,
2538c2ecf20Sopenharmony_ci	 * this works only if the user space portmapper is rpcbind, and
2548c2ecf20Sopenharmony_ci	 * it's listening on AF_LOCAL on the named socket.
2558c2ecf20Sopenharmony_ci	 */
2568c2ecf20Sopenharmony_ci	clnt = rpc_create(&args);
2578c2ecf20Sopenharmony_ci	if (IS_ERR(clnt)) {
2588c2ecf20Sopenharmony_ci		result = PTR_ERR(clnt);
2598c2ecf20Sopenharmony_ci		goto out;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
2638c2ecf20Sopenharmony_ci	if (IS_ERR(clnt4))
2648c2ecf20Sopenharmony_ci		clnt4 = NULL;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	rpcb_set_local(net, clnt, clnt4, true);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ciout:
2698c2ecf20Sopenharmony_ci	return result;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci/*
2738c2ecf20Sopenharmony_ci * Returns zero on success, otherwise a negative errno value
2748c2ecf20Sopenharmony_ci * is returned.
2758c2ecf20Sopenharmony_ci */
2768c2ecf20Sopenharmony_cistatic int rpcb_create_local_net(struct net *net)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	static const struct sockaddr_in rpcb_inaddr_loopback = {
2798c2ecf20Sopenharmony_ci		.sin_family		= AF_INET,
2808c2ecf20Sopenharmony_ci		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
2818c2ecf20Sopenharmony_ci		.sin_port		= htons(RPCBIND_PORT),
2828c2ecf20Sopenharmony_ci	};
2838c2ecf20Sopenharmony_ci	struct rpc_create_args args = {
2848c2ecf20Sopenharmony_ci		.net		= net,
2858c2ecf20Sopenharmony_ci		.protocol	= XPRT_TRANSPORT_TCP,
2868c2ecf20Sopenharmony_ci		.address	= (struct sockaddr *)&rpcb_inaddr_loopback,
2878c2ecf20Sopenharmony_ci		.addrsize	= sizeof(rpcb_inaddr_loopback),
2888c2ecf20Sopenharmony_ci		.servername	= "localhost",
2898c2ecf20Sopenharmony_ci		.program	= &rpcb_program,
2908c2ecf20Sopenharmony_ci		.version	= RPCBVERS_2,
2918c2ecf20Sopenharmony_ci		.authflavor	= RPC_AUTH_UNIX,
2928c2ecf20Sopenharmony_ci		.cred		= current_cred(),
2938c2ecf20Sopenharmony_ci		.flags		= RPC_CLNT_CREATE_NOPING,
2948c2ecf20Sopenharmony_ci	};
2958c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt, *clnt4;
2968c2ecf20Sopenharmony_ci	int result = 0;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	clnt = rpc_create(&args);
2998c2ecf20Sopenharmony_ci	if (IS_ERR(clnt)) {
3008c2ecf20Sopenharmony_ci		result = PTR_ERR(clnt);
3018c2ecf20Sopenharmony_ci		goto out;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/*
3058c2ecf20Sopenharmony_ci	 * This results in an RPC ping.  On systems running portmapper,
3068c2ecf20Sopenharmony_ci	 * the v4 ping will fail.  Proceed anyway, but disallow rpcb
3078c2ecf20Sopenharmony_ci	 * v4 upcalls.
3088c2ecf20Sopenharmony_ci	 */
3098c2ecf20Sopenharmony_ci	clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
3108c2ecf20Sopenharmony_ci	if (IS_ERR(clnt4))
3118c2ecf20Sopenharmony_ci		clnt4 = NULL;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	rpcb_set_local(net, clnt, clnt4, false);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ciout:
3168c2ecf20Sopenharmony_ci	return result;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci/*
3208c2ecf20Sopenharmony_ci * Returns zero on success, otherwise a negative errno value
3218c2ecf20Sopenharmony_ci * is returned.
3228c2ecf20Sopenharmony_ci */
3238c2ecf20Sopenharmony_ciint rpcb_create_local(struct net *net)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	static DEFINE_MUTEX(rpcb_create_local_mutex);
3268c2ecf20Sopenharmony_ci	int result = 0;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (rpcb_get_local(net))
3298c2ecf20Sopenharmony_ci		return result;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	mutex_lock(&rpcb_create_local_mutex);
3328c2ecf20Sopenharmony_ci	if (rpcb_get_local(net))
3338c2ecf20Sopenharmony_ci		goto out;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (rpcb_create_local_unix(net) != 0)
3368c2ecf20Sopenharmony_ci		result = rpcb_create_local_net(net);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ciout:
3398c2ecf20Sopenharmony_ci	mutex_unlock(&rpcb_create_local_mutex);
3408c2ecf20Sopenharmony_ci	return result;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic struct rpc_clnt *rpcb_create(struct net *net, const char *nodename,
3448c2ecf20Sopenharmony_ci				    const char *hostname,
3458c2ecf20Sopenharmony_ci				    struct sockaddr *srvaddr, size_t salen,
3468c2ecf20Sopenharmony_ci				    int proto, u32 version,
3478c2ecf20Sopenharmony_ci				    const struct cred *cred)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct rpc_create_args args = {
3508c2ecf20Sopenharmony_ci		.net		= net,
3518c2ecf20Sopenharmony_ci		.protocol	= proto,
3528c2ecf20Sopenharmony_ci		.address	= srvaddr,
3538c2ecf20Sopenharmony_ci		.addrsize	= salen,
3548c2ecf20Sopenharmony_ci		.servername	= hostname,
3558c2ecf20Sopenharmony_ci		.nodename	= nodename,
3568c2ecf20Sopenharmony_ci		.program	= &rpcb_program,
3578c2ecf20Sopenharmony_ci		.version	= version,
3588c2ecf20Sopenharmony_ci		.authflavor	= RPC_AUTH_UNIX,
3598c2ecf20Sopenharmony_ci		.cred		= cred,
3608c2ecf20Sopenharmony_ci		.flags		= (RPC_CLNT_CREATE_NOPING |
3618c2ecf20Sopenharmony_ci					RPC_CLNT_CREATE_NONPRIVPORT),
3628c2ecf20Sopenharmony_ci	};
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	switch (srvaddr->sa_family) {
3658c2ecf20Sopenharmony_ci	case AF_INET:
3668c2ecf20Sopenharmony_ci		((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
3678c2ecf20Sopenharmony_ci		break;
3688c2ecf20Sopenharmony_ci	case AF_INET6:
3698c2ecf20Sopenharmony_ci		((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
3708c2ecf20Sopenharmony_ci		break;
3718c2ecf20Sopenharmony_ci	default:
3728c2ecf20Sopenharmony_ci		return ERR_PTR(-EAFNOSUPPORT);
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return rpc_create(&args);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	int flags = RPC_TASK_NOCONNECT;
3818c2ecf20Sopenharmony_ci	int error, result = 0;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (is_set || !sn->rpcb_is_af_local)
3848c2ecf20Sopenharmony_ci		flags = RPC_TASK_SOFTCONN;
3858c2ecf20Sopenharmony_ci	msg->rpc_resp = &result;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	error = rpc_call_sync(clnt, msg, flags);
3888c2ecf20Sopenharmony_ci	if (error < 0)
3898c2ecf20Sopenharmony_ci		return error;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if (!result)
3928c2ecf20Sopenharmony_ci		return -EACCES;
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/**
3978c2ecf20Sopenharmony_ci * rpcb_register - set or unset a port registration with the local rpcbind svc
3988c2ecf20Sopenharmony_ci * @net: target network namespace
3998c2ecf20Sopenharmony_ci * @prog: RPC program number to bind
4008c2ecf20Sopenharmony_ci * @vers: RPC version number to bind
4018c2ecf20Sopenharmony_ci * @prot: transport protocol to register
4028c2ecf20Sopenharmony_ci * @port: port value to register
4038c2ecf20Sopenharmony_ci *
4048c2ecf20Sopenharmony_ci * Returns zero if the registration request was dispatched successfully
4058c2ecf20Sopenharmony_ci * and the rpcbind daemon returned success.  Otherwise, returns an errno
4068c2ecf20Sopenharmony_ci * value that reflects the nature of the error (request could not be
4078c2ecf20Sopenharmony_ci * dispatched, timed out, or rpcbind returned an error).
4088c2ecf20Sopenharmony_ci *
4098c2ecf20Sopenharmony_ci * RPC services invoke this function to advertise their contact
4108c2ecf20Sopenharmony_ci * information via the system's rpcbind daemon.  RPC services
4118c2ecf20Sopenharmony_ci * invoke this function once for each [program, version, transport]
4128c2ecf20Sopenharmony_ci * tuple they wish to advertise.
4138c2ecf20Sopenharmony_ci *
4148c2ecf20Sopenharmony_ci * Callers may also unregister RPC services that are no longer
4158c2ecf20Sopenharmony_ci * available by setting the passed-in port to zero.  This removes
4168c2ecf20Sopenharmony_ci * all registered transports for [program, version] from the local
4178c2ecf20Sopenharmony_ci * rpcbind database.
4188c2ecf20Sopenharmony_ci *
4198c2ecf20Sopenharmony_ci * This function uses rpcbind protocol version 2 to contact the
4208c2ecf20Sopenharmony_ci * local rpcbind daemon.
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci * Registration works over both AF_INET and AF_INET6, and services
4238c2ecf20Sopenharmony_ci * registered via this function are advertised as available for any
4248c2ecf20Sopenharmony_ci * address.  If the local rpcbind daemon is listening on AF_INET6,
4258c2ecf20Sopenharmony_ci * services registered via this function will be advertised on
4268c2ecf20Sopenharmony_ci * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
4278c2ecf20Sopenharmony_ci * addresses).
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_ciint rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct rpcbind_args map = {
4328c2ecf20Sopenharmony_ci		.r_prog		= prog,
4338c2ecf20Sopenharmony_ci		.r_vers		= vers,
4348c2ecf20Sopenharmony_ci		.r_prot		= prot,
4358c2ecf20Sopenharmony_ci		.r_port		= port,
4368c2ecf20Sopenharmony_ci	};
4378c2ecf20Sopenharmony_ci	struct rpc_message msg = {
4388c2ecf20Sopenharmony_ci		.rpc_argp	= &map,
4398c2ecf20Sopenharmony_ci	};
4408c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
4418c2ecf20Sopenharmony_ci	bool is_set = false;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	trace_pmap_register(prog, vers, prot, port);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
4468c2ecf20Sopenharmony_ci	if (port != 0) {
4478c2ecf20Sopenharmony_ci		msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
4488c2ecf20Sopenharmony_ci		is_set = true;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	return rpcb_register_call(sn, sn->rpcb_local_clnt, &msg, is_set);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci/*
4558c2ecf20Sopenharmony_ci * Fill in AF_INET family-specific arguments to register
4568c2ecf20Sopenharmony_ci */
4578c2ecf20Sopenharmony_cistatic int rpcb_register_inet4(struct sunrpc_net *sn,
4588c2ecf20Sopenharmony_ci			       const struct sockaddr *sap,
4598c2ecf20Sopenharmony_ci			       struct rpc_message *msg)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
4628c2ecf20Sopenharmony_ci	struct rpcbind_args *map = msg->rpc_argp;
4638c2ecf20Sopenharmony_ci	unsigned short port = ntohs(sin->sin_port);
4648c2ecf20Sopenharmony_ci	bool is_set = false;
4658c2ecf20Sopenharmony_ci	int result;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
4708c2ecf20Sopenharmony_ci	if (port != 0) {
4718c2ecf20Sopenharmony_ci		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
4728c2ecf20Sopenharmony_ci		is_set = true;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
4768c2ecf20Sopenharmony_ci	kfree(map->r_addr);
4778c2ecf20Sopenharmony_ci	return result;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci/*
4818c2ecf20Sopenharmony_ci * Fill in AF_INET6 family-specific arguments to register
4828c2ecf20Sopenharmony_ci */
4838c2ecf20Sopenharmony_cistatic int rpcb_register_inet6(struct sunrpc_net *sn,
4848c2ecf20Sopenharmony_ci			       const struct sockaddr *sap,
4858c2ecf20Sopenharmony_ci			       struct rpc_message *msg)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
4888c2ecf20Sopenharmony_ci	struct rpcbind_args *map = msg->rpc_argp;
4898c2ecf20Sopenharmony_ci	unsigned short port = ntohs(sin6->sin6_port);
4908c2ecf20Sopenharmony_ci	bool is_set = false;
4918c2ecf20Sopenharmony_ci	int result;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
4968c2ecf20Sopenharmony_ci	if (port != 0) {
4978c2ecf20Sopenharmony_ci		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
4988c2ecf20Sopenharmony_ci		is_set = true;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
5028c2ecf20Sopenharmony_ci	kfree(map->r_addr);
5038c2ecf20Sopenharmony_ci	return result;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
5078c2ecf20Sopenharmony_ci					     struct rpc_message *msg)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct rpcbind_args *map = msg->rpc_argp;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	trace_rpcb_unregister(map->r_prog, map->r_vers, map->r_netid);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	map->r_addr = "";
5148c2ecf20Sopenharmony_ci	msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, false);
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/**
5208c2ecf20Sopenharmony_ci * rpcb_v4_register - set or unset a port registration with the local rpcbind
5218c2ecf20Sopenharmony_ci * @net: target network namespace
5228c2ecf20Sopenharmony_ci * @program: RPC program number of service to (un)register
5238c2ecf20Sopenharmony_ci * @version: RPC version number of service to (un)register
5248c2ecf20Sopenharmony_ci * @address: address family, IP address, and port to (un)register
5258c2ecf20Sopenharmony_ci * @netid: netid of transport protocol to (un)register
5268c2ecf20Sopenharmony_ci *
5278c2ecf20Sopenharmony_ci * Returns zero if the registration request was dispatched successfully
5288c2ecf20Sopenharmony_ci * and the rpcbind daemon returned success.  Otherwise, returns an errno
5298c2ecf20Sopenharmony_ci * value that reflects the nature of the error (request could not be
5308c2ecf20Sopenharmony_ci * dispatched, timed out, or rpcbind returned an error).
5318c2ecf20Sopenharmony_ci *
5328c2ecf20Sopenharmony_ci * RPC services invoke this function to advertise their contact
5338c2ecf20Sopenharmony_ci * information via the system's rpcbind daemon.  RPC services
5348c2ecf20Sopenharmony_ci * invoke this function once for each [program, version, address,
5358c2ecf20Sopenharmony_ci * netid] tuple they wish to advertise.
5368c2ecf20Sopenharmony_ci *
5378c2ecf20Sopenharmony_ci * Callers may also unregister RPC services that are registered at a
5388c2ecf20Sopenharmony_ci * specific address by setting the port number in @address to zero.
5398c2ecf20Sopenharmony_ci * They may unregister all registered protocol families at once for
5408c2ecf20Sopenharmony_ci * a service by passing a NULL @address argument.  If @netid is ""
5418c2ecf20Sopenharmony_ci * then all netids for [program, version, address] are unregistered.
5428c2ecf20Sopenharmony_ci *
5438c2ecf20Sopenharmony_ci * This function uses rpcbind protocol version 4 to contact the
5448c2ecf20Sopenharmony_ci * local rpcbind daemon.  The local rpcbind daemon must support
5458c2ecf20Sopenharmony_ci * version 4 of the rpcbind protocol in order for these functions
5468c2ecf20Sopenharmony_ci * to register a service successfully.
5478c2ecf20Sopenharmony_ci *
5488c2ecf20Sopenharmony_ci * Supported netids include "udp" and "tcp" for UDP and TCP over
5498c2ecf20Sopenharmony_ci * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6,
5508c2ecf20Sopenharmony_ci * respectively.
5518c2ecf20Sopenharmony_ci *
5528c2ecf20Sopenharmony_ci * The contents of @address determine the address family and the
5538c2ecf20Sopenharmony_ci * port to be registered.  The usual practice is to pass INADDR_ANY
5548c2ecf20Sopenharmony_ci * as the raw address, but specifying a non-zero address is also
5558c2ecf20Sopenharmony_ci * supported by this API if the caller wishes to advertise an RPC
5568c2ecf20Sopenharmony_ci * service on a specific network interface.
5578c2ecf20Sopenharmony_ci *
5588c2ecf20Sopenharmony_ci * Note that passing in INADDR_ANY does not create the same service
5598c2ecf20Sopenharmony_ci * registration as IN6ADDR_ANY.  The former advertises an RPC
5608c2ecf20Sopenharmony_ci * service on any IPv4 address, but not on IPv6.  The latter
5618c2ecf20Sopenharmony_ci * advertises the service on all IPv4 and IPv6 addresses.
5628c2ecf20Sopenharmony_ci */
5638c2ecf20Sopenharmony_ciint rpcb_v4_register(struct net *net, const u32 program, const u32 version,
5648c2ecf20Sopenharmony_ci		     const struct sockaddr *address, const char *netid)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct rpcbind_args map = {
5678c2ecf20Sopenharmony_ci		.r_prog		= program,
5688c2ecf20Sopenharmony_ci		.r_vers		= version,
5698c2ecf20Sopenharmony_ci		.r_netid	= netid,
5708c2ecf20Sopenharmony_ci		.r_owner	= RPCB_OWNER_STRING,
5718c2ecf20Sopenharmony_ci	};
5728c2ecf20Sopenharmony_ci	struct rpc_message msg = {
5738c2ecf20Sopenharmony_ci		.rpc_argp	= &map,
5748c2ecf20Sopenharmony_ci	};
5758c2ecf20Sopenharmony_ci	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (sn->rpcb_local_clnt4 == NULL)
5788c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if (address == NULL)
5818c2ecf20Sopenharmony_ci		return rpcb_unregister_all_protofamilies(sn, &msg);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	trace_rpcb_register(map.r_prog, map.r_vers, map.r_addr, map.r_netid);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	switch (address->sa_family) {
5868c2ecf20Sopenharmony_ci	case AF_INET:
5878c2ecf20Sopenharmony_ci		return rpcb_register_inet4(sn, address, &msg);
5888c2ecf20Sopenharmony_ci	case AF_INET6:
5898c2ecf20Sopenharmony_ci		return rpcb_register_inet6(sn, address, &msg);
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	return -EAFNOSUPPORT;
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt,
5968c2ecf20Sopenharmony_ci		struct rpcbind_args *map, const struct rpc_procinfo *proc)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	struct rpc_message msg = {
5998c2ecf20Sopenharmony_ci		.rpc_proc = proc,
6008c2ecf20Sopenharmony_ci		.rpc_argp = map,
6018c2ecf20Sopenharmony_ci		.rpc_resp = map,
6028c2ecf20Sopenharmony_ci	};
6038c2ecf20Sopenharmony_ci	struct rpc_task_setup task_setup_data = {
6048c2ecf20Sopenharmony_ci		.rpc_client = rpcb_clnt,
6058c2ecf20Sopenharmony_ci		.rpc_message = &msg,
6068c2ecf20Sopenharmony_ci		.callback_ops = &rpcb_getport_ops,
6078c2ecf20Sopenharmony_ci		.callback_data = map,
6088c2ecf20Sopenharmony_ci		.flags = RPC_TASK_ASYNC | RPC_TASK_SOFTCONN,
6098c2ecf20Sopenharmony_ci	};
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return rpc_run_task(&task_setup_data);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci/*
6158c2ecf20Sopenharmony_ci * In the case where rpc clients have been cloned, we want to make
6168c2ecf20Sopenharmony_ci * sure that we use the program number/version etc of the actual
6178c2ecf20Sopenharmony_ci * owner of the xprt. To do so, we walk back up the tree of parents
6188c2ecf20Sopenharmony_ci * to find whoever created the transport and/or whoever has the
6198c2ecf20Sopenharmony_ci * autobind flag set.
6208c2ecf20Sopenharmony_ci */
6218c2ecf20Sopenharmony_cistatic struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct rpc_clnt *parent = clnt->cl_parent;
6248c2ecf20Sopenharmony_ci	struct rpc_xprt_switch *xps = rcu_access_pointer(clnt->cl_xpi.xpi_xpswitch);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	while (parent != clnt) {
6278c2ecf20Sopenharmony_ci		if (rcu_access_pointer(parent->cl_xpi.xpi_xpswitch) != xps)
6288c2ecf20Sopenharmony_ci			break;
6298c2ecf20Sopenharmony_ci		if (clnt->cl_autobind)
6308c2ecf20Sopenharmony_ci			break;
6318c2ecf20Sopenharmony_ci		clnt = parent;
6328c2ecf20Sopenharmony_ci		parent = parent->cl_parent;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci	return clnt;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci/**
6388c2ecf20Sopenharmony_ci * rpcb_getport_async - obtain the port for a given RPC service on a given host
6398c2ecf20Sopenharmony_ci * @task: task that is waiting for portmapper request
6408c2ecf20Sopenharmony_ci *
6418c2ecf20Sopenharmony_ci * This one can be called for an ongoing RPC request, and can be used in
6428c2ecf20Sopenharmony_ci * an async (rpciod) context.
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_civoid rpcb_getport_async(struct rpc_task *task)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	struct rpc_clnt *clnt;
6478c2ecf20Sopenharmony_ci	const struct rpc_procinfo *proc;
6488c2ecf20Sopenharmony_ci	u32 bind_version;
6498c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt;
6508c2ecf20Sopenharmony_ci	struct rpc_clnt	*rpcb_clnt;
6518c2ecf20Sopenharmony_ci	struct rpcbind_args *map;
6528c2ecf20Sopenharmony_ci	struct rpc_task	*child;
6538c2ecf20Sopenharmony_ci	struct sockaddr_storage addr;
6548c2ecf20Sopenharmony_ci	struct sockaddr *sap = (struct sockaddr *)&addr;
6558c2ecf20Sopenharmony_ci	size_t salen;
6568c2ecf20Sopenharmony_ci	int status;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	rcu_read_lock();
6598c2ecf20Sopenharmony_ci	clnt = rpcb_find_transport_owner(task->tk_client);
6608c2ecf20Sopenharmony_ci	rcu_read_unlock();
6618c2ecf20Sopenharmony_ci	xprt = xprt_get(task->tk_xprt);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	/* Put self on the wait queue to ensure we get notified if
6648c2ecf20Sopenharmony_ci	 * some other task is already attempting to bind the port */
6658c2ecf20Sopenharmony_ci	rpc_sleep_on_timeout(&xprt->binding, task,
6668c2ecf20Sopenharmony_ci			NULL, jiffies + xprt->bind_timeout);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	if (xprt_test_and_set_binding(xprt)) {
6698c2ecf20Sopenharmony_ci		xprt_put(xprt);
6708c2ecf20Sopenharmony_ci		return;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	/* Someone else may have bound if we slept */
6748c2ecf20Sopenharmony_ci	if (xprt_bound(xprt)) {
6758c2ecf20Sopenharmony_ci		status = 0;
6768c2ecf20Sopenharmony_ci		goto bailout_nofree;
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* Parent transport's destination address */
6808c2ecf20Sopenharmony_ci	salen = rpc_peeraddr(clnt, sap, sizeof(addr));
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	/* Don't ever use rpcbind v2 for AF_INET6 requests */
6838c2ecf20Sopenharmony_ci	switch (sap->sa_family) {
6848c2ecf20Sopenharmony_ci	case AF_INET:
6858c2ecf20Sopenharmony_ci		proc = rpcb_next_version[xprt->bind_index].rpc_proc;
6868c2ecf20Sopenharmony_ci		bind_version = rpcb_next_version[xprt->bind_index].rpc_vers;
6878c2ecf20Sopenharmony_ci		break;
6888c2ecf20Sopenharmony_ci	case AF_INET6:
6898c2ecf20Sopenharmony_ci		proc = rpcb_next_version6[xprt->bind_index].rpc_proc;
6908c2ecf20Sopenharmony_ci		bind_version = rpcb_next_version6[xprt->bind_index].rpc_vers;
6918c2ecf20Sopenharmony_ci		break;
6928c2ecf20Sopenharmony_ci	default:
6938c2ecf20Sopenharmony_ci		status = -EAFNOSUPPORT;
6948c2ecf20Sopenharmony_ci		goto bailout_nofree;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci	if (proc == NULL) {
6978c2ecf20Sopenharmony_ci		xprt->bind_index = 0;
6988c2ecf20Sopenharmony_ci		status = -EPFNOSUPPORT;
6998c2ecf20Sopenharmony_ci		goto bailout_nofree;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	trace_rpcb_getport(clnt, task, bind_version);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	rpcb_clnt = rpcb_create(xprt->xprt_net,
7058c2ecf20Sopenharmony_ci				clnt->cl_nodename,
7068c2ecf20Sopenharmony_ci				xprt->servername, sap, salen,
7078c2ecf20Sopenharmony_ci				xprt->prot, bind_version,
7088c2ecf20Sopenharmony_ci				clnt->cl_cred);
7098c2ecf20Sopenharmony_ci	if (IS_ERR(rpcb_clnt)) {
7108c2ecf20Sopenharmony_ci		status = PTR_ERR(rpcb_clnt);
7118c2ecf20Sopenharmony_ci		goto bailout_nofree;
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	map = kzalloc(sizeof(struct rpcbind_args), GFP_NOFS);
7158c2ecf20Sopenharmony_ci	if (!map) {
7168c2ecf20Sopenharmony_ci		status = -ENOMEM;
7178c2ecf20Sopenharmony_ci		goto bailout_release_client;
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci	map->r_prog = clnt->cl_prog;
7208c2ecf20Sopenharmony_ci	map->r_vers = clnt->cl_vers;
7218c2ecf20Sopenharmony_ci	map->r_prot = xprt->prot;
7228c2ecf20Sopenharmony_ci	map->r_port = 0;
7238c2ecf20Sopenharmony_ci	map->r_xprt = xprt;
7248c2ecf20Sopenharmony_ci	map->r_status = -EIO;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	switch (bind_version) {
7278c2ecf20Sopenharmony_ci	case RPCBVERS_4:
7288c2ecf20Sopenharmony_ci	case RPCBVERS_3:
7298c2ecf20Sopenharmony_ci		map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID];
7308c2ecf20Sopenharmony_ci		map->r_addr = rpc_sockaddr2uaddr(sap, GFP_NOFS);
7318c2ecf20Sopenharmony_ci		if (!map->r_addr) {
7328c2ecf20Sopenharmony_ci			status = -ENOMEM;
7338c2ecf20Sopenharmony_ci			goto bailout_free_args;
7348c2ecf20Sopenharmony_ci		}
7358c2ecf20Sopenharmony_ci		map->r_owner = "";
7368c2ecf20Sopenharmony_ci		break;
7378c2ecf20Sopenharmony_ci	case RPCBVERS_2:
7388c2ecf20Sopenharmony_ci		map->r_addr = NULL;
7398c2ecf20Sopenharmony_ci		break;
7408c2ecf20Sopenharmony_ci	default:
7418c2ecf20Sopenharmony_ci		BUG();
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	child = rpcb_call_async(rpcb_clnt, map, proc);
7458c2ecf20Sopenharmony_ci	rpc_release_client(rpcb_clnt);
7468c2ecf20Sopenharmony_ci	if (IS_ERR(child)) {
7478c2ecf20Sopenharmony_ci		/* rpcb_map_release() has freed the arguments */
7488c2ecf20Sopenharmony_ci		return;
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	xprt->stat.bind_count++;
7528c2ecf20Sopenharmony_ci	rpc_put_task(child);
7538c2ecf20Sopenharmony_ci	return;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cibailout_free_args:
7568c2ecf20Sopenharmony_ci	kfree(map);
7578c2ecf20Sopenharmony_cibailout_release_client:
7588c2ecf20Sopenharmony_ci	rpc_release_client(rpcb_clnt);
7598c2ecf20Sopenharmony_cibailout_nofree:
7608c2ecf20Sopenharmony_ci	rpcb_wake_rpcbind_waiters(xprt, status);
7618c2ecf20Sopenharmony_ci	task->tk_status = status;
7628c2ecf20Sopenharmony_ci	xprt_put(xprt);
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpcb_getport_async);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci/*
7678c2ecf20Sopenharmony_ci * Rpcbind child task calls this callback via tk_exit.
7688c2ecf20Sopenharmony_ci */
7698c2ecf20Sopenharmony_cistatic void rpcb_getport_done(struct rpc_task *child, void *data)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct rpcbind_args *map = data;
7728c2ecf20Sopenharmony_ci	struct rpc_xprt *xprt = map->r_xprt;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	map->r_status = child->tk_status;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* Garbage reply: retry with a lesser rpcbind version */
7778c2ecf20Sopenharmony_ci	if (map->r_status == -EIO)
7788c2ecf20Sopenharmony_ci		map->r_status = -EPROTONOSUPPORT;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/* rpcbind server doesn't support this rpcbind protocol version */
7818c2ecf20Sopenharmony_ci	if (map->r_status == -EPROTONOSUPPORT)
7828c2ecf20Sopenharmony_ci		xprt->bind_index++;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (map->r_status < 0) {
7858c2ecf20Sopenharmony_ci		/* rpcbind server not available on remote host? */
7868c2ecf20Sopenharmony_ci		map->r_port = 0;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	} else if (map->r_port == 0) {
7898c2ecf20Sopenharmony_ci		/* Requested RPC service wasn't registered on remote host */
7908c2ecf20Sopenharmony_ci		map->r_status = -EACCES;
7918c2ecf20Sopenharmony_ci	} else {
7928c2ecf20Sopenharmony_ci		/* Succeeded */
7938c2ecf20Sopenharmony_ci		map->r_status = 0;
7948c2ecf20Sopenharmony_ci	}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	trace_rpcb_setport(child, map->r_status, map->r_port);
7978c2ecf20Sopenharmony_ci	xprt->ops->set_port(xprt, map->r_port);
7988c2ecf20Sopenharmony_ci	if (map->r_port)
7998c2ecf20Sopenharmony_ci		xprt_set_bound(xprt);
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci/*
8038c2ecf20Sopenharmony_ci * XDR functions for rpcbind
8048c2ecf20Sopenharmony_ci */
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,
8078c2ecf20Sopenharmony_ci			     const void *data)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	const struct rpcbind_args *rpcb = data;
8108c2ecf20Sopenharmony_ci	__be32 *p;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2);
8138c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(rpcb->r_prog);
8148c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(rpcb->r_vers);
8158c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(rpcb->r_prot);
8168c2ecf20Sopenharmony_ci	*p   = cpu_to_be32(rpcb->r_port);
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
8208c2ecf20Sopenharmony_ci			    void *data)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	struct rpcbind_args *rpcb = data;
8238c2ecf20Sopenharmony_ci	unsigned long port;
8248c2ecf20Sopenharmony_ci	__be32 *p;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	rpcb->r_port = 0;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
8298c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
8308c2ecf20Sopenharmony_ci		return -EIO;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	port = be32_to_cpup(p);
8338c2ecf20Sopenharmony_ci	if (unlikely(port > USHRT_MAX))
8348c2ecf20Sopenharmony_ci		return -EIO;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	rpcb->r_port = port;
8378c2ecf20Sopenharmony_ci	return 0;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,
8418c2ecf20Sopenharmony_ci			void *data)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	unsigned int *boolp = data;
8448c2ecf20Sopenharmony_ci	__be32 *p;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
8478c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
8488c2ecf20Sopenharmony_ci		return -EIO;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	*boolp = 0;
8518c2ecf20Sopenharmony_ci	if (*p != xdr_zero)
8528c2ecf20Sopenharmony_ci		*boolp = 1;
8538c2ecf20Sopenharmony_ci	return 0;
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_cistatic void encode_rpcb_string(struct xdr_stream *xdr, const char *string,
8578c2ecf20Sopenharmony_ci			       const u32 maxstrlen)
8588c2ecf20Sopenharmony_ci{
8598c2ecf20Sopenharmony_ci	__be32 *p;
8608c2ecf20Sopenharmony_ci	u32 len;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	len = strlen(string);
8638c2ecf20Sopenharmony_ci	WARN_ON_ONCE(len > maxstrlen);
8648c2ecf20Sopenharmony_ci	if (len > maxstrlen)
8658c2ecf20Sopenharmony_ci		/* truncate and hope for the best */
8668c2ecf20Sopenharmony_ci		len = maxstrlen;
8678c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + len);
8688c2ecf20Sopenharmony_ci	xdr_encode_opaque(p, string, len);
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
8728c2ecf20Sopenharmony_ci			     const void *data)
8738c2ecf20Sopenharmony_ci{
8748c2ecf20Sopenharmony_ci	const struct rpcbind_args *rpcb = data;
8758c2ecf20Sopenharmony_ci	__be32 *p;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, (RPCB_program_sz + RPCB_version_sz) << 2);
8788c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(rpcb->r_prog);
8798c2ecf20Sopenharmony_ci	*p = cpu_to_be32(rpcb->r_vers);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	encode_rpcb_string(xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN);
8828c2ecf20Sopenharmony_ci	encode_rpcb_string(xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN);
8838c2ecf20Sopenharmony_ci	encode_rpcb_string(xdr, rpcb->r_owner, RPCB_MAXOWNERLEN);
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
8878c2ecf20Sopenharmony_ci			    void *data)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	struct rpcbind_args *rpcb = data;
8908c2ecf20Sopenharmony_ci	struct sockaddr_storage address;
8918c2ecf20Sopenharmony_ci	struct sockaddr *sap = (struct sockaddr *)&address;
8928c2ecf20Sopenharmony_ci	__be32 *p;
8938c2ecf20Sopenharmony_ci	u32 len;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	rpcb->r_port = 0;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
8988c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
8998c2ecf20Sopenharmony_ci		goto out_fail;
9008c2ecf20Sopenharmony_ci	len = be32_to_cpup(p);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	/*
9038c2ecf20Sopenharmony_ci	 * If the returned universal address is a null string,
9048c2ecf20Sopenharmony_ci	 * the requested RPC service was not registered.
9058c2ecf20Sopenharmony_ci	 */
9068c2ecf20Sopenharmony_ci	if (len == 0)
9078c2ecf20Sopenharmony_ci		return 0;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	if (unlikely(len > RPCBIND_MAXUADDRLEN))
9108c2ecf20Sopenharmony_ci		goto out_fail;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, len);
9138c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
9148c2ecf20Sopenharmony_ci		goto out_fail;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len,
9178c2ecf20Sopenharmony_ci				sap, sizeof(address)) == 0)
9188c2ecf20Sopenharmony_ci		goto out_fail;
9198c2ecf20Sopenharmony_ci	rpcb->r_port = rpc_get_port(sap);
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	return 0;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ciout_fail:
9248c2ecf20Sopenharmony_ci	return -EIO;
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci/*
9288c2ecf20Sopenharmony_ci * Not all rpcbind procedures described in RFC 1833 are implemented
9298c2ecf20Sopenharmony_ci * since the Linux kernel RPC code requires only these.
9308c2ecf20Sopenharmony_ci */
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic const struct rpc_procinfo rpcb_procedures2[] = {
9338c2ecf20Sopenharmony_ci	[RPCBPROC_SET] = {
9348c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_SET,
9358c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_mapping,
9368c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_set,
9378c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_mappingargs_sz,
9388c2ecf20Sopenharmony_ci		.p_replen	= RPCB_setres_sz,
9398c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_SET,
9408c2ecf20Sopenharmony_ci		.p_timer	= 0,
9418c2ecf20Sopenharmony_ci		.p_name		= "SET",
9428c2ecf20Sopenharmony_ci	},
9438c2ecf20Sopenharmony_ci	[RPCBPROC_UNSET] = {
9448c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_UNSET,
9458c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_mapping,
9468c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_set,
9478c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_mappingargs_sz,
9488c2ecf20Sopenharmony_ci		.p_replen	= RPCB_setres_sz,
9498c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_UNSET,
9508c2ecf20Sopenharmony_ci		.p_timer	= 0,
9518c2ecf20Sopenharmony_ci		.p_name		= "UNSET",
9528c2ecf20Sopenharmony_ci	},
9538c2ecf20Sopenharmony_ci	[RPCBPROC_GETPORT] = {
9548c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_GETPORT,
9558c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_mapping,
9568c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_getport,
9578c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_mappingargs_sz,
9588c2ecf20Sopenharmony_ci		.p_replen	= RPCB_getportres_sz,
9598c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_GETPORT,
9608c2ecf20Sopenharmony_ci		.p_timer	= 0,
9618c2ecf20Sopenharmony_ci		.p_name		= "GETPORT",
9628c2ecf20Sopenharmony_ci	},
9638c2ecf20Sopenharmony_ci};
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic const struct rpc_procinfo rpcb_procedures3[] = {
9668c2ecf20Sopenharmony_ci	[RPCBPROC_SET] = {
9678c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_SET,
9688c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_getaddr,
9698c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_set,
9708c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_getaddrargs_sz,
9718c2ecf20Sopenharmony_ci		.p_replen	= RPCB_setres_sz,
9728c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_SET,
9738c2ecf20Sopenharmony_ci		.p_timer	= 0,
9748c2ecf20Sopenharmony_ci		.p_name		= "SET",
9758c2ecf20Sopenharmony_ci	},
9768c2ecf20Sopenharmony_ci	[RPCBPROC_UNSET] = {
9778c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_UNSET,
9788c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_getaddr,
9798c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_set,
9808c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_getaddrargs_sz,
9818c2ecf20Sopenharmony_ci		.p_replen	= RPCB_setres_sz,
9828c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_UNSET,
9838c2ecf20Sopenharmony_ci		.p_timer	= 0,
9848c2ecf20Sopenharmony_ci		.p_name		= "UNSET",
9858c2ecf20Sopenharmony_ci	},
9868c2ecf20Sopenharmony_ci	[RPCBPROC_GETADDR] = {
9878c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_GETADDR,
9888c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_getaddr,
9898c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_getaddr,
9908c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_getaddrargs_sz,
9918c2ecf20Sopenharmony_ci		.p_replen	= RPCB_getaddrres_sz,
9928c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_GETADDR,
9938c2ecf20Sopenharmony_ci		.p_timer	= 0,
9948c2ecf20Sopenharmony_ci		.p_name		= "GETADDR",
9958c2ecf20Sopenharmony_ci	},
9968c2ecf20Sopenharmony_ci};
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic const struct rpc_procinfo rpcb_procedures4[] = {
9998c2ecf20Sopenharmony_ci	[RPCBPROC_SET] = {
10008c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_SET,
10018c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_getaddr,
10028c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_set,
10038c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_getaddrargs_sz,
10048c2ecf20Sopenharmony_ci		.p_replen	= RPCB_setres_sz,
10058c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_SET,
10068c2ecf20Sopenharmony_ci		.p_timer	= 0,
10078c2ecf20Sopenharmony_ci		.p_name		= "SET",
10088c2ecf20Sopenharmony_ci	},
10098c2ecf20Sopenharmony_ci	[RPCBPROC_UNSET] = {
10108c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_UNSET,
10118c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_getaddr,
10128c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_set,
10138c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_getaddrargs_sz,
10148c2ecf20Sopenharmony_ci		.p_replen	= RPCB_setres_sz,
10158c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_UNSET,
10168c2ecf20Sopenharmony_ci		.p_timer	= 0,
10178c2ecf20Sopenharmony_ci		.p_name		= "UNSET",
10188c2ecf20Sopenharmony_ci	},
10198c2ecf20Sopenharmony_ci	[RPCBPROC_GETADDR] = {
10208c2ecf20Sopenharmony_ci		.p_proc		= RPCBPROC_GETADDR,
10218c2ecf20Sopenharmony_ci		.p_encode	= rpcb_enc_getaddr,
10228c2ecf20Sopenharmony_ci		.p_decode	= rpcb_dec_getaddr,
10238c2ecf20Sopenharmony_ci		.p_arglen	= RPCB_getaddrargs_sz,
10248c2ecf20Sopenharmony_ci		.p_replen	= RPCB_getaddrres_sz,
10258c2ecf20Sopenharmony_ci		.p_statidx	= RPCBPROC_GETADDR,
10268c2ecf20Sopenharmony_ci		.p_timer	= 0,
10278c2ecf20Sopenharmony_ci		.p_name		= "GETADDR",
10288c2ecf20Sopenharmony_ci	},
10298c2ecf20Sopenharmony_ci};
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_cistatic const struct rpcb_info rpcb_next_version[] = {
10328c2ecf20Sopenharmony_ci	{
10338c2ecf20Sopenharmony_ci		.rpc_vers	= RPCBVERS_2,
10348c2ecf20Sopenharmony_ci		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
10358c2ecf20Sopenharmony_ci	},
10368c2ecf20Sopenharmony_ci	{
10378c2ecf20Sopenharmony_ci		.rpc_proc	= NULL,
10388c2ecf20Sopenharmony_ci	},
10398c2ecf20Sopenharmony_ci};
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic const struct rpcb_info rpcb_next_version6[] = {
10428c2ecf20Sopenharmony_ci	{
10438c2ecf20Sopenharmony_ci		.rpc_vers	= RPCBVERS_4,
10448c2ecf20Sopenharmony_ci		.rpc_proc	= &rpcb_procedures4[RPCBPROC_GETADDR],
10458c2ecf20Sopenharmony_ci	},
10468c2ecf20Sopenharmony_ci	{
10478c2ecf20Sopenharmony_ci		.rpc_vers	= RPCBVERS_3,
10488c2ecf20Sopenharmony_ci		.rpc_proc	= &rpcb_procedures3[RPCBPROC_GETADDR],
10498c2ecf20Sopenharmony_ci	},
10508c2ecf20Sopenharmony_ci	{
10518c2ecf20Sopenharmony_ci		.rpc_proc	= NULL,
10528c2ecf20Sopenharmony_ci	},
10538c2ecf20Sopenharmony_ci};
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic unsigned int rpcb_version2_counts[ARRAY_SIZE(rpcb_procedures2)];
10568c2ecf20Sopenharmony_cistatic const struct rpc_version rpcb_version2 = {
10578c2ecf20Sopenharmony_ci	.number		= RPCBVERS_2,
10588c2ecf20Sopenharmony_ci	.nrprocs	= ARRAY_SIZE(rpcb_procedures2),
10598c2ecf20Sopenharmony_ci	.procs		= rpcb_procedures2,
10608c2ecf20Sopenharmony_ci	.counts		= rpcb_version2_counts,
10618c2ecf20Sopenharmony_ci};
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_cistatic unsigned int rpcb_version3_counts[ARRAY_SIZE(rpcb_procedures3)];
10648c2ecf20Sopenharmony_cistatic const struct rpc_version rpcb_version3 = {
10658c2ecf20Sopenharmony_ci	.number		= RPCBVERS_3,
10668c2ecf20Sopenharmony_ci	.nrprocs	= ARRAY_SIZE(rpcb_procedures3),
10678c2ecf20Sopenharmony_ci	.procs		= rpcb_procedures3,
10688c2ecf20Sopenharmony_ci	.counts		= rpcb_version3_counts,
10698c2ecf20Sopenharmony_ci};
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cistatic unsigned int rpcb_version4_counts[ARRAY_SIZE(rpcb_procedures4)];
10728c2ecf20Sopenharmony_cistatic const struct rpc_version rpcb_version4 = {
10738c2ecf20Sopenharmony_ci	.number		= RPCBVERS_4,
10748c2ecf20Sopenharmony_ci	.nrprocs	= ARRAY_SIZE(rpcb_procedures4),
10758c2ecf20Sopenharmony_ci	.procs		= rpcb_procedures4,
10768c2ecf20Sopenharmony_ci	.counts		= rpcb_version4_counts,
10778c2ecf20Sopenharmony_ci};
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_cistatic const struct rpc_version *rpcb_version[] = {
10808c2ecf20Sopenharmony_ci	NULL,
10818c2ecf20Sopenharmony_ci	NULL,
10828c2ecf20Sopenharmony_ci	&rpcb_version2,
10838c2ecf20Sopenharmony_ci	&rpcb_version3,
10848c2ecf20Sopenharmony_ci	&rpcb_version4
10858c2ecf20Sopenharmony_ci};
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic struct rpc_stat rpcb_stats;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_cistatic const struct rpc_program rpcb_program = {
10908c2ecf20Sopenharmony_ci	.name		= "rpcbind",
10918c2ecf20Sopenharmony_ci	.number		= RPCBIND_PROGRAM,
10928c2ecf20Sopenharmony_ci	.nrvers		= ARRAY_SIZE(rpcb_version),
10938c2ecf20Sopenharmony_ci	.version	= rpcb_version,
10948c2ecf20Sopenharmony_ci	.stats		= &rpcb_stats,
10958c2ecf20Sopenharmony_ci};
1096