18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/fs/lockd/clntxdr.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * XDR functions to encode/decode NLM version 3 RPC arguments and results.
68c2ecf20Sopenharmony_ci * NLM version 3 is backwards compatible with NLM versions 1 and 2.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * NLM client-side only.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2010, Oracle.  All rights reserved.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <linux/sunrpc/xdr.h>
158c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h>
168c2ecf20Sopenharmony_ci#include <linux/sunrpc/stats.h>
178c2ecf20Sopenharmony_ci#include <linux/lockd/lockd.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <uapi/linux/nfs2.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define NLMDBG_FACILITY		NLMDBG_XDR
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
248c2ecf20Sopenharmony_ci#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
258c2ecf20Sopenharmony_ci#endif
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * Declare the space requirements for NLM arguments and replies as
298c2ecf20Sopenharmony_ci * number of 32bit-words
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci#define NLM_cookie_sz		(1+(NLM_MAXCOOKIELEN>>2))
328c2ecf20Sopenharmony_ci#define NLM_caller_sz		(1+(NLMCLNT_OHSIZE>>2))
338c2ecf20Sopenharmony_ci#define NLM_owner_sz		(1+(NLMCLNT_OHSIZE>>2))
348c2ecf20Sopenharmony_ci#define NLM_fhandle_sz		(1+(NFS2_FHSIZE>>2))
358c2ecf20Sopenharmony_ci#define NLM_lock_sz		(3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz)
368c2ecf20Sopenharmony_ci#define NLM_holder_sz		(4+NLM_owner_sz)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define NLM_testargs_sz		(NLM_cookie_sz+1+NLM_lock_sz)
398c2ecf20Sopenharmony_ci#define NLM_lockargs_sz		(NLM_cookie_sz+4+NLM_lock_sz)
408c2ecf20Sopenharmony_ci#define NLM_cancargs_sz		(NLM_cookie_sz+2+NLM_lock_sz)
418c2ecf20Sopenharmony_ci#define NLM_unlockargs_sz	(NLM_cookie_sz+NLM_lock_sz)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define NLM_testres_sz		(NLM_cookie_sz+1+NLM_holder_sz)
448c2ecf20Sopenharmony_ci#define NLM_res_sz		(NLM_cookie_sz+1)
458c2ecf20Sopenharmony_ci#define NLM_norep_sz		(0)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic s32 loff_t_to_s32(loff_t offset)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	s32 res;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (offset >= NLM_OFFSET_MAX)
538c2ecf20Sopenharmony_ci		res = NLM_OFFSET_MAX;
548c2ecf20Sopenharmony_ci	else if (offset <= -NLM_OFFSET_MAX)
558c2ecf20Sopenharmony_ci		res = -NLM_OFFSET_MAX;
568c2ecf20Sopenharmony_ci	else
578c2ecf20Sopenharmony_ci		res = offset;
588c2ecf20Sopenharmony_ci	return res;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic void nlm_compute_offsets(const struct nlm_lock *lock,
628c2ecf20Sopenharmony_ci				u32 *l_offset, u32 *l_len)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	const struct file_lock *fl = &lock->fl;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	*l_offset = loff_t_to_s32(fl->fl_start);
678c2ecf20Sopenharmony_ci	if (fl->fl_end == OFFSET_MAX)
688c2ecf20Sopenharmony_ci		*l_len = 0;
698c2ecf20Sopenharmony_ci	else
708c2ecf20Sopenharmony_ci		*l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * Encode/decode NLMv3 basic data types
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci * Basic NLMv3 data types are not defined in an IETF standards
778c2ecf20Sopenharmony_ci * document.  X/Open has a description of these data types that
788c2ecf20Sopenharmony_ci * is useful.  See Chapter 10 of "Protocols for Interworking:
798c2ecf20Sopenharmony_ci * XNFS, Version 3W".
808c2ecf20Sopenharmony_ci *
818c2ecf20Sopenharmony_ci * Not all basic data types have their own encoding and decoding
828c2ecf20Sopenharmony_ci * functions.  For run-time efficiency, some data types are encoded
838c2ecf20Sopenharmony_ci * or decoded inline.
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void encode_bool(struct xdr_stream *xdr, const int value)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	__be32 *p;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
918c2ecf20Sopenharmony_ci	*p = value ? xdr_one : xdr_zero;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic void encode_int32(struct xdr_stream *xdr, const s32 value)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	__be32 *p;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
998c2ecf20Sopenharmony_ci	*p = cpu_to_be32(value);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/*
1038c2ecf20Sopenharmony_ci *	typedef opaque netobj<MAXNETOBJ_SZ>
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_cistatic void encode_netobj(struct xdr_stream *xdr,
1068c2ecf20Sopenharmony_ci			  const u8 *data, const unsigned int length)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	__be32 *p;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + length);
1118c2ecf20Sopenharmony_ci	xdr_encode_opaque(p, data, length);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic int decode_netobj(struct xdr_stream *xdr,
1158c2ecf20Sopenharmony_ci			 struct xdr_netobj *obj)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	ssize_t ret;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	ret = xdr_stream_decode_opaque_inline(xdr, (void *)&obj->data,
1208c2ecf20Sopenharmony_ci			XDR_MAX_NETOBJ);
1218c2ecf20Sopenharmony_ci	if (unlikely(ret < 0))
1228c2ecf20Sopenharmony_ci		return -EIO;
1238c2ecf20Sopenharmony_ci	obj->len = ret;
1248c2ecf20Sopenharmony_ci	return 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci *	netobj cookie;
1298c2ecf20Sopenharmony_ci */
1308c2ecf20Sopenharmony_cistatic void encode_cookie(struct xdr_stream *xdr,
1318c2ecf20Sopenharmony_ci			  const struct nlm_cookie *cookie)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int decode_cookie(struct xdr_stream *xdr,
1378c2ecf20Sopenharmony_ci			 struct nlm_cookie *cookie)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	u32 length;
1408c2ecf20Sopenharmony_ci	__be32 *p;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
1438c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
1448c2ecf20Sopenharmony_ci		goto out_overflow;
1458c2ecf20Sopenharmony_ci	length = be32_to_cpup(p++);
1468c2ecf20Sopenharmony_ci	/* apparently HPUX can return empty cookies */
1478c2ecf20Sopenharmony_ci	if (length == 0)
1488c2ecf20Sopenharmony_ci		goto out_hpux;
1498c2ecf20Sopenharmony_ci	if (length > NLM_MAXCOOKIELEN)
1508c2ecf20Sopenharmony_ci		goto out_size;
1518c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, length);
1528c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
1538c2ecf20Sopenharmony_ci		goto out_overflow;
1548c2ecf20Sopenharmony_ci	cookie->len = length;
1558c2ecf20Sopenharmony_ci	memcpy(cookie->data, p, length);
1568c2ecf20Sopenharmony_ci	return 0;
1578c2ecf20Sopenharmony_ciout_hpux:
1588c2ecf20Sopenharmony_ci	cookie->len = 4;
1598c2ecf20Sopenharmony_ci	memset(cookie->data, 0, 4);
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ciout_size:
1628c2ecf20Sopenharmony_ci	dprintk("NFS: returned cookie was too long: %u\n", length);
1638c2ecf20Sopenharmony_ci	return -EIO;
1648c2ecf20Sopenharmony_ciout_overflow:
1658c2ecf20Sopenharmony_ci	return -EIO;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/*
1698c2ecf20Sopenharmony_ci *	netobj fh;
1708c2ecf20Sopenharmony_ci */
1718c2ecf20Sopenharmony_cistatic void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/*
1778c2ecf20Sopenharmony_ci *	enum nlm_stats {
1788c2ecf20Sopenharmony_ci *		LCK_GRANTED = 0,
1798c2ecf20Sopenharmony_ci *		LCK_DENIED = 1,
1808c2ecf20Sopenharmony_ci *		LCK_DENIED_NOLOCKS = 2,
1818c2ecf20Sopenharmony_ci *		LCK_BLOCKED = 3,
1828c2ecf20Sopenharmony_ci *		LCK_DENIED_GRACE_PERIOD = 4
1838c2ecf20Sopenharmony_ci *	};
1848c2ecf20Sopenharmony_ci *
1858c2ecf20Sopenharmony_ci *
1868c2ecf20Sopenharmony_ci *	struct nlm_stat {
1878c2ecf20Sopenharmony_ci *		nlm_stats stat;
1888c2ecf20Sopenharmony_ci *	};
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * NB: we don't swap bytes for the NLM status values.  The upper
1918c2ecf20Sopenharmony_ci * layers deal directly with the status value in network byte
1928c2ecf20Sopenharmony_ci * order.
1938c2ecf20Sopenharmony_ci */
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void encode_nlm_stat(struct xdr_stream *xdr,
1968c2ecf20Sopenharmony_ci			    const __be32 stat)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	__be32 *p;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	WARN_ON_ONCE(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD);
2018c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
2028c2ecf20Sopenharmony_ci	*p = stat;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int decode_nlm_stat(struct xdr_stream *xdr,
2068c2ecf20Sopenharmony_ci			   __be32 *stat)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	__be32 *p;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
2118c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
2128c2ecf20Sopenharmony_ci		goto out_overflow;
2138c2ecf20Sopenharmony_ci	if (unlikely(ntohl(*p) > ntohl(nlm_lck_denied_grace_period)))
2148c2ecf20Sopenharmony_ci		goto out_enum;
2158c2ecf20Sopenharmony_ci	*stat = *p;
2168c2ecf20Sopenharmony_ci	return 0;
2178c2ecf20Sopenharmony_ciout_enum:
2188c2ecf20Sopenharmony_ci	dprintk("%s: server returned invalid nlm_stats value: %u\n",
2198c2ecf20Sopenharmony_ci		__func__, be32_to_cpup(p));
2208c2ecf20Sopenharmony_ci	return -EIO;
2218c2ecf20Sopenharmony_ciout_overflow:
2228c2ecf20Sopenharmony_ci	return -EIO;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/*
2268c2ecf20Sopenharmony_ci *	struct nlm_holder {
2278c2ecf20Sopenharmony_ci *		bool exclusive;
2288c2ecf20Sopenharmony_ci *		int uppid;
2298c2ecf20Sopenharmony_ci *		netobj oh;
2308c2ecf20Sopenharmony_ci *		unsigned l_offset;
2318c2ecf20Sopenharmony_ci *		unsigned l_len;
2328c2ecf20Sopenharmony_ci *	};
2338c2ecf20Sopenharmony_ci */
2348c2ecf20Sopenharmony_cistatic void encode_nlm_holder(struct xdr_stream *xdr,
2358c2ecf20Sopenharmony_ci			      const struct nlm_res *result)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	const struct nlm_lock *lock = &result->lock;
2388c2ecf20Sopenharmony_ci	u32 l_offset, l_len;
2398c2ecf20Sopenharmony_ci	__be32 *p;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
2428c2ecf20Sopenharmony_ci	encode_int32(xdr, lock->svid);
2438c2ecf20Sopenharmony_ci	encode_netobj(xdr, lock->oh.data, lock->oh.len);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4);
2468c2ecf20Sopenharmony_ci	nlm_compute_offsets(lock, &l_offset, &l_len);
2478c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(l_offset);
2488c2ecf20Sopenharmony_ci	*p   = cpu_to_be32(l_len);
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct nlm_lock *lock = &result->lock;
2548c2ecf20Sopenharmony_ci	struct file_lock *fl = &lock->fl;
2558c2ecf20Sopenharmony_ci	u32 exclusive, l_offset, l_len;
2568c2ecf20Sopenharmony_ci	int error;
2578c2ecf20Sopenharmony_ci	__be32 *p;
2588c2ecf20Sopenharmony_ci	s32 end;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	memset(lock, 0, sizeof(*lock));
2618c2ecf20Sopenharmony_ci	locks_init_lock(fl);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 + 4);
2648c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
2658c2ecf20Sopenharmony_ci		goto out_overflow;
2668c2ecf20Sopenharmony_ci	exclusive = be32_to_cpup(p++);
2678c2ecf20Sopenharmony_ci	lock->svid = be32_to_cpup(p);
2688c2ecf20Sopenharmony_ci	fl->fl_pid = (pid_t)lock->svid;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	error = decode_netobj(xdr, &lock->oh);
2718c2ecf20Sopenharmony_ci	if (unlikely(error))
2728c2ecf20Sopenharmony_ci		goto out;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 + 4);
2758c2ecf20Sopenharmony_ci	if (unlikely(p == NULL))
2768c2ecf20Sopenharmony_ci		goto out_overflow;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	fl->fl_flags = FL_POSIX;
2798c2ecf20Sopenharmony_ci	fl->fl_type  = exclusive != 0 ? F_WRLCK : F_RDLCK;
2808c2ecf20Sopenharmony_ci	l_offset = be32_to_cpup(p++);
2818c2ecf20Sopenharmony_ci	l_len = be32_to_cpup(p);
2828c2ecf20Sopenharmony_ci	end = l_offset + l_len - 1;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	fl->fl_start = (loff_t)l_offset;
2858c2ecf20Sopenharmony_ci	if (l_len == 0 || end < 0)
2868c2ecf20Sopenharmony_ci		fl->fl_end = OFFSET_MAX;
2878c2ecf20Sopenharmony_ci	else
2888c2ecf20Sopenharmony_ci		fl->fl_end = (loff_t)end;
2898c2ecf20Sopenharmony_ci	error = 0;
2908c2ecf20Sopenharmony_ciout:
2918c2ecf20Sopenharmony_ci	return error;
2928c2ecf20Sopenharmony_ciout_overflow:
2938c2ecf20Sopenharmony_ci	return -EIO;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/*
2978c2ecf20Sopenharmony_ci *	string caller_name<LM_MAXSTRLEN>;
2988c2ecf20Sopenharmony_ci */
2998c2ecf20Sopenharmony_cistatic void encode_caller_name(struct xdr_stream *xdr, const char *name)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	/* NB: client-side does not set lock->len */
3028c2ecf20Sopenharmony_ci	u32 length = strlen(name);
3038c2ecf20Sopenharmony_ci	__be32 *p;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + length);
3068c2ecf20Sopenharmony_ci	xdr_encode_opaque(p, name, length);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci/*
3108c2ecf20Sopenharmony_ci *	struct nlm_lock {
3118c2ecf20Sopenharmony_ci *		string caller_name<LM_MAXSTRLEN>;
3128c2ecf20Sopenharmony_ci *		netobj fh;
3138c2ecf20Sopenharmony_ci *		netobj oh;
3148c2ecf20Sopenharmony_ci *		int uppid;
3158c2ecf20Sopenharmony_ci *		unsigned l_offset;
3168c2ecf20Sopenharmony_ci *		unsigned l_len;
3178c2ecf20Sopenharmony_ci *	};
3188c2ecf20Sopenharmony_ci */
3198c2ecf20Sopenharmony_cistatic void encode_nlm_lock(struct xdr_stream *xdr,
3208c2ecf20Sopenharmony_ci			    const struct nlm_lock *lock)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	u32 l_offset, l_len;
3238c2ecf20Sopenharmony_ci	__be32 *p;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	encode_caller_name(xdr, lock->caller);
3268c2ecf20Sopenharmony_ci	encode_fh(xdr, &lock->fh);
3278c2ecf20Sopenharmony_ci	encode_netobj(xdr, lock->oh.data, lock->oh.len);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4 + 4);
3308c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(lock->svid);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	nlm_compute_offsets(lock, &l_offset, &l_len);
3338c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(l_offset);
3348c2ecf20Sopenharmony_ci	*p   = cpu_to_be32(l_len);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci/*
3398c2ecf20Sopenharmony_ci * NLMv3 XDR encode functions
3408c2ecf20Sopenharmony_ci *
3418c2ecf20Sopenharmony_ci * NLMv3 argument types are defined in Chapter 10 of The Open Group's
3428c2ecf20Sopenharmony_ci * "Protocols for Interworking: XNFS, Version 3W".
3438c2ecf20Sopenharmony_ci */
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci/*
3468c2ecf20Sopenharmony_ci *	struct nlm_testargs {
3478c2ecf20Sopenharmony_ci *		netobj cookie;
3488c2ecf20Sopenharmony_ci *		bool exclusive;
3498c2ecf20Sopenharmony_ci *		struct nlm_lock alock;
3508c2ecf20Sopenharmony_ci *	};
3518c2ecf20Sopenharmony_ci */
3528c2ecf20Sopenharmony_cistatic void nlm_xdr_enc_testargs(struct rpc_rqst *req,
3538c2ecf20Sopenharmony_ci				 struct xdr_stream *xdr,
3548c2ecf20Sopenharmony_ci				 const void *data)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	const struct nlm_args *args = data;
3578c2ecf20Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
3608c2ecf20Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
3618c2ecf20Sopenharmony_ci	encode_nlm_lock(xdr, lock);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci/*
3658c2ecf20Sopenharmony_ci *	struct nlm_lockargs {
3668c2ecf20Sopenharmony_ci *		netobj cookie;
3678c2ecf20Sopenharmony_ci *		bool block;
3688c2ecf20Sopenharmony_ci *		bool exclusive;
3698c2ecf20Sopenharmony_ci *		struct nlm_lock alock;
3708c2ecf20Sopenharmony_ci *		bool reclaim;
3718c2ecf20Sopenharmony_ci *		int state;
3728c2ecf20Sopenharmony_ci *	};
3738c2ecf20Sopenharmony_ci */
3748c2ecf20Sopenharmony_cistatic void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
3758c2ecf20Sopenharmony_ci				 struct xdr_stream *xdr,
3768c2ecf20Sopenharmony_ci				 const void *data)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	const struct nlm_args *args = data;
3798c2ecf20Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
3828c2ecf20Sopenharmony_ci	encode_bool(xdr, args->block);
3838c2ecf20Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
3848c2ecf20Sopenharmony_ci	encode_nlm_lock(xdr, lock);
3858c2ecf20Sopenharmony_ci	encode_bool(xdr, args->reclaim);
3868c2ecf20Sopenharmony_ci	encode_int32(xdr, args->state);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci/*
3908c2ecf20Sopenharmony_ci *	struct nlm_cancargs {
3918c2ecf20Sopenharmony_ci *		netobj cookie;
3928c2ecf20Sopenharmony_ci *		bool block;
3938c2ecf20Sopenharmony_ci *		bool exclusive;
3948c2ecf20Sopenharmony_ci *		struct nlm_lock alock;
3958c2ecf20Sopenharmony_ci *	};
3968c2ecf20Sopenharmony_ci */
3978c2ecf20Sopenharmony_cistatic void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
3988c2ecf20Sopenharmony_ci				 struct xdr_stream *xdr,
3998c2ecf20Sopenharmony_ci				 const void *data)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	const struct nlm_args *args = data;
4028c2ecf20Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
4058c2ecf20Sopenharmony_ci	encode_bool(xdr, args->block);
4068c2ecf20Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
4078c2ecf20Sopenharmony_ci	encode_nlm_lock(xdr, lock);
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/*
4118c2ecf20Sopenharmony_ci *	struct nlm_unlockargs {
4128c2ecf20Sopenharmony_ci *		netobj cookie;
4138c2ecf20Sopenharmony_ci *		struct nlm_lock alock;
4148c2ecf20Sopenharmony_ci *	};
4158c2ecf20Sopenharmony_ci */
4168c2ecf20Sopenharmony_cistatic void nlm_xdr_enc_unlockargs(struct rpc_rqst *req,
4178c2ecf20Sopenharmony_ci				   struct xdr_stream *xdr,
4188c2ecf20Sopenharmony_ci				   const void *data)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	const struct nlm_args *args = data;
4218c2ecf20Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
4248c2ecf20Sopenharmony_ci	encode_nlm_lock(xdr, lock);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/*
4288c2ecf20Sopenharmony_ci *	struct nlm_res {
4298c2ecf20Sopenharmony_ci *		netobj cookie;
4308c2ecf20Sopenharmony_ci *		nlm_stat stat;
4318c2ecf20Sopenharmony_ci *	};
4328c2ecf20Sopenharmony_ci */
4338c2ecf20Sopenharmony_cistatic void nlm_xdr_enc_res(struct rpc_rqst *req,
4348c2ecf20Sopenharmony_ci			    struct xdr_stream *xdr,
4358c2ecf20Sopenharmony_ci			    const void *data)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	const struct nlm_res *result = data;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	encode_cookie(xdr, &result->cookie);
4408c2ecf20Sopenharmony_ci	encode_nlm_stat(xdr, result->status);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci/*
4448c2ecf20Sopenharmony_ci *	union nlm_testrply switch (nlm_stats stat) {
4458c2ecf20Sopenharmony_ci *	case LCK_DENIED:
4468c2ecf20Sopenharmony_ci *		struct nlm_holder holder;
4478c2ecf20Sopenharmony_ci *	default:
4488c2ecf20Sopenharmony_ci *		void;
4498c2ecf20Sopenharmony_ci *	};
4508c2ecf20Sopenharmony_ci *
4518c2ecf20Sopenharmony_ci *	struct nlm_testres {
4528c2ecf20Sopenharmony_ci *		netobj cookie;
4538c2ecf20Sopenharmony_ci *		nlm_testrply test_stat;
4548c2ecf20Sopenharmony_ci *	};
4558c2ecf20Sopenharmony_ci */
4568c2ecf20Sopenharmony_cistatic void encode_nlm_testrply(struct xdr_stream *xdr,
4578c2ecf20Sopenharmony_ci				const struct nlm_res *result)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	if (result->status == nlm_lck_denied)
4608c2ecf20Sopenharmony_ci		encode_nlm_holder(xdr, result);
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic void nlm_xdr_enc_testres(struct rpc_rqst *req,
4648c2ecf20Sopenharmony_ci				struct xdr_stream *xdr,
4658c2ecf20Sopenharmony_ci				const void *data)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	const struct nlm_res *result = data;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	encode_cookie(xdr, &result->cookie);
4708c2ecf20Sopenharmony_ci	encode_nlm_stat(xdr, result->status);
4718c2ecf20Sopenharmony_ci	encode_nlm_testrply(xdr, result);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci/*
4768c2ecf20Sopenharmony_ci * NLMv3 XDR decode functions
4778c2ecf20Sopenharmony_ci *
4788c2ecf20Sopenharmony_ci * NLMv3 result types are defined in Chapter 10 of The Open Group's
4798c2ecf20Sopenharmony_ci * "Protocols for Interworking: XNFS, Version 3W".
4808c2ecf20Sopenharmony_ci */
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci/*
4838c2ecf20Sopenharmony_ci *	union nlm_testrply switch (nlm_stats stat) {
4848c2ecf20Sopenharmony_ci *	case LCK_DENIED:
4858c2ecf20Sopenharmony_ci *		struct nlm_holder holder;
4868c2ecf20Sopenharmony_ci *	default:
4878c2ecf20Sopenharmony_ci *		void;
4888c2ecf20Sopenharmony_ci *	};
4898c2ecf20Sopenharmony_ci *
4908c2ecf20Sopenharmony_ci *	struct nlm_testres {
4918c2ecf20Sopenharmony_ci *		netobj cookie;
4928c2ecf20Sopenharmony_ci *		nlm_testrply test_stat;
4938c2ecf20Sopenharmony_ci *	};
4948c2ecf20Sopenharmony_ci */
4958c2ecf20Sopenharmony_cistatic int decode_nlm_testrply(struct xdr_stream *xdr,
4968c2ecf20Sopenharmony_ci			       struct nlm_res *result)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	int error;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	error = decode_nlm_stat(xdr, &result->status);
5018c2ecf20Sopenharmony_ci	if (unlikely(error))
5028c2ecf20Sopenharmony_ci		goto out;
5038c2ecf20Sopenharmony_ci	if (result->status == nlm_lck_denied)
5048c2ecf20Sopenharmony_ci		error = decode_nlm_holder(xdr, result);
5058c2ecf20Sopenharmony_ciout:
5068c2ecf20Sopenharmony_ci	return error;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int nlm_xdr_dec_testres(struct rpc_rqst *req,
5108c2ecf20Sopenharmony_ci			       struct xdr_stream *xdr,
5118c2ecf20Sopenharmony_ci			       void *data)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	struct nlm_res *result = data;
5148c2ecf20Sopenharmony_ci	int error;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	error = decode_cookie(xdr, &result->cookie);
5178c2ecf20Sopenharmony_ci	if (unlikely(error))
5188c2ecf20Sopenharmony_ci		goto out;
5198c2ecf20Sopenharmony_ci	error = decode_nlm_testrply(xdr, result);
5208c2ecf20Sopenharmony_ciout:
5218c2ecf20Sopenharmony_ci	return error;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci/*
5258c2ecf20Sopenharmony_ci *	struct nlm_res {
5268c2ecf20Sopenharmony_ci *		netobj cookie;
5278c2ecf20Sopenharmony_ci *		nlm_stat stat;
5288c2ecf20Sopenharmony_ci *	};
5298c2ecf20Sopenharmony_ci */
5308c2ecf20Sopenharmony_cistatic int nlm_xdr_dec_res(struct rpc_rqst *req,
5318c2ecf20Sopenharmony_ci			   struct xdr_stream *xdr,
5328c2ecf20Sopenharmony_ci			   void *data)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct nlm_res *result = data;
5358c2ecf20Sopenharmony_ci	int error;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	error = decode_cookie(xdr, &result->cookie);
5388c2ecf20Sopenharmony_ci	if (unlikely(error))
5398c2ecf20Sopenharmony_ci		goto out;
5408c2ecf20Sopenharmony_ci	error = decode_nlm_stat(xdr, &result->status);
5418c2ecf20Sopenharmony_ciout:
5428c2ecf20Sopenharmony_ci	return error;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci/*
5478c2ecf20Sopenharmony_ci * For NLM, a void procedure really returns nothing
5488c2ecf20Sopenharmony_ci */
5498c2ecf20Sopenharmony_ci#define nlm_xdr_dec_norep	NULL
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci#define PROC(proc, argtype, restype)	\
5528c2ecf20Sopenharmony_ci[NLMPROC_##proc] = {							\
5538c2ecf20Sopenharmony_ci	.p_proc      = NLMPROC_##proc,					\
5548c2ecf20Sopenharmony_ci	.p_encode    = nlm_xdr_enc_##argtype,		\
5558c2ecf20Sopenharmony_ci	.p_decode    = nlm_xdr_dec_##restype,				\
5568c2ecf20Sopenharmony_ci	.p_arglen    = NLM_##argtype##_sz,				\
5578c2ecf20Sopenharmony_ci	.p_replen    = NLM_##restype##_sz,				\
5588c2ecf20Sopenharmony_ci	.p_statidx   = NLMPROC_##proc,					\
5598c2ecf20Sopenharmony_ci	.p_name      = #proc,						\
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic const struct rpc_procinfo nlm_procedures[] = {
5638c2ecf20Sopenharmony_ci	PROC(TEST,		testargs,	testres),
5648c2ecf20Sopenharmony_ci	PROC(LOCK,		lockargs,	res),
5658c2ecf20Sopenharmony_ci	PROC(CANCEL,		cancargs,	res),
5668c2ecf20Sopenharmony_ci	PROC(UNLOCK,		unlockargs,	res),
5678c2ecf20Sopenharmony_ci	PROC(GRANTED,		testargs,	res),
5688c2ecf20Sopenharmony_ci	PROC(TEST_MSG,		testargs,	norep),
5698c2ecf20Sopenharmony_ci	PROC(LOCK_MSG,		lockargs,	norep),
5708c2ecf20Sopenharmony_ci	PROC(CANCEL_MSG,	cancargs,	norep),
5718c2ecf20Sopenharmony_ci	PROC(UNLOCK_MSG,	unlockargs,	norep),
5728c2ecf20Sopenharmony_ci	PROC(GRANTED_MSG,	testargs,	norep),
5738c2ecf20Sopenharmony_ci	PROC(TEST_RES,		testres,	norep),
5748c2ecf20Sopenharmony_ci	PROC(LOCK_RES,		res,		norep),
5758c2ecf20Sopenharmony_ci	PROC(CANCEL_RES,	res,		norep),
5768c2ecf20Sopenharmony_ci	PROC(UNLOCK_RES,	res,		norep),
5778c2ecf20Sopenharmony_ci	PROC(GRANTED_RES,	res,		norep),
5788c2ecf20Sopenharmony_ci};
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic unsigned int nlm_version1_counts[ARRAY_SIZE(nlm_procedures)];
5818c2ecf20Sopenharmony_cistatic const struct rpc_version	nlm_version1 = {
5828c2ecf20Sopenharmony_ci	.number		= 1,
5838c2ecf20Sopenharmony_ci	.nrprocs	= ARRAY_SIZE(nlm_procedures),
5848c2ecf20Sopenharmony_ci	.procs		= nlm_procedures,
5858c2ecf20Sopenharmony_ci	.counts		= nlm_version1_counts,
5868c2ecf20Sopenharmony_ci};
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic unsigned int nlm_version3_counts[ARRAY_SIZE(nlm_procedures)];
5898c2ecf20Sopenharmony_cistatic const struct rpc_version	nlm_version3 = {
5908c2ecf20Sopenharmony_ci	.number		= 3,
5918c2ecf20Sopenharmony_ci	.nrprocs	= ARRAY_SIZE(nlm_procedures),
5928c2ecf20Sopenharmony_ci	.procs		= nlm_procedures,
5938c2ecf20Sopenharmony_ci	.counts		= nlm_version3_counts,
5948c2ecf20Sopenharmony_ci};
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cistatic const struct rpc_version	*nlm_versions[] = {
5978c2ecf20Sopenharmony_ci	[1] = &nlm_version1,
5988c2ecf20Sopenharmony_ci	[3] = &nlm_version3,
5998c2ecf20Sopenharmony_ci#ifdef CONFIG_LOCKD_V4
6008c2ecf20Sopenharmony_ci	[4] = &nlm_version4,
6018c2ecf20Sopenharmony_ci#endif
6028c2ecf20Sopenharmony_ci};
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic struct rpc_stat		nlm_rpc_stats;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ciconst struct rpc_program	nlm_program = {
6078c2ecf20Sopenharmony_ci	.name		= "lockd",
6088c2ecf20Sopenharmony_ci	.number		= NLM_PROGRAM,
6098c2ecf20Sopenharmony_ci	.nrvers		= ARRAY_SIZE(nlm_versions),
6108c2ecf20Sopenharmony_ci	.version	= nlm_versions,
6118c2ecf20Sopenharmony_ci	.stats		= &nlm_rpc_stats,
6128c2ecf20Sopenharmony_ci};
613