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