162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/fs/lockd/clnt4xdr.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * XDR functions to encode/decode NLM version 4 RPC arguments and results.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * NLM client-side only.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (C) 2010, Oracle.  All rights reserved.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/types.h>
1362306a36Sopenharmony_ci#include <linux/sunrpc/xdr.h>
1462306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h>
1562306a36Sopenharmony_ci#include <linux/sunrpc/stats.h>
1662306a36Sopenharmony_ci#include <linux/lockd/lockd.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <uapi/linux/nfs3.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define NLMDBG_FACILITY		NLMDBG_XDR
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
2362306a36Sopenharmony_ci#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
2462306a36Sopenharmony_ci#endif
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN)
2762306a36Sopenharmony_ci#  error "NLM host name cannot be larger than NLM's maximum string length!"
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * Declare the space requirements for NLM arguments and replies as
3262306a36Sopenharmony_ci * number of 32bit-words
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci#define NLM4_void_sz		(0)
3562306a36Sopenharmony_ci#define NLM4_cookie_sz		(1+(NLM_MAXCOOKIELEN>>2))
3662306a36Sopenharmony_ci#define NLM4_caller_sz		(1+(NLMCLNT_OHSIZE>>2))
3762306a36Sopenharmony_ci#define NLM4_owner_sz		(1+(NLMCLNT_OHSIZE>>2))
3862306a36Sopenharmony_ci#define NLM4_fhandle_sz		(1+(NFS3_FHSIZE>>2))
3962306a36Sopenharmony_ci#define NLM4_lock_sz		(5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz)
4062306a36Sopenharmony_ci#define NLM4_holder_sz		(6+NLM4_owner_sz)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define NLM4_testargs_sz	(NLM4_cookie_sz+1+NLM4_lock_sz)
4362306a36Sopenharmony_ci#define NLM4_lockargs_sz	(NLM4_cookie_sz+4+NLM4_lock_sz)
4462306a36Sopenharmony_ci#define NLM4_cancargs_sz	(NLM4_cookie_sz+2+NLM4_lock_sz)
4562306a36Sopenharmony_ci#define NLM4_unlockargs_sz	(NLM4_cookie_sz+NLM4_lock_sz)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define NLM4_testres_sz		(NLM4_cookie_sz+1+NLM4_holder_sz)
4862306a36Sopenharmony_ci#define NLM4_res_sz		(NLM4_cookie_sz+1)
4962306a36Sopenharmony_ci#define NLM4_norep_sz		(0)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic s64 loff_t_to_s64(loff_t offset)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	s64 res;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (offset >= NLM4_OFFSET_MAX)
5762306a36Sopenharmony_ci		res = NLM4_OFFSET_MAX;
5862306a36Sopenharmony_ci	else if (offset <= -NLM4_OFFSET_MAX)
5962306a36Sopenharmony_ci		res = -NLM4_OFFSET_MAX;
6062306a36Sopenharmony_ci	else
6162306a36Sopenharmony_ci		res = offset;
6262306a36Sopenharmony_ci	return res;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void nlm4_compute_offsets(const struct nlm_lock *lock,
6662306a36Sopenharmony_ci				 u64 *l_offset, u64 *l_len)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	const struct file_lock *fl = &lock->fl;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	*l_offset = loff_t_to_s64(fl->fl_start);
7162306a36Sopenharmony_ci	if (fl->fl_end == OFFSET_MAX)
7262306a36Sopenharmony_ci		*l_len = 0;
7362306a36Sopenharmony_ci	else
7462306a36Sopenharmony_ci		*l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * Encode/decode NLMv4 basic data types
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * Basic NLMv4 data types are defined in Appendix II, section 6.1.4
8162306a36Sopenharmony_ci * of RFC 1813: "NFS Version 3 Protocol Specification" and in Chapter
8262306a36Sopenharmony_ci * 10 of X/Open's "Protocols for Interworking: XNFS, Version 3W".
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * Not all basic data types have their own encoding and decoding
8562306a36Sopenharmony_ci * functions.  For run-time efficiency, some data types are encoded
8662306a36Sopenharmony_ci * or decoded inline.
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void encode_bool(struct xdr_stream *xdr, const int value)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	__be32 *p;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
9462306a36Sopenharmony_ci	*p = value ? xdr_one : xdr_zero;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void encode_int32(struct xdr_stream *xdr, const s32 value)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	__be32 *p;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
10262306a36Sopenharmony_ci	*p = cpu_to_be32(value);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci *	typedef opaque netobj<MAXNETOBJ_SZ>
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_cistatic void encode_netobj(struct xdr_stream *xdr,
10962306a36Sopenharmony_ci			  const u8 *data, const unsigned int length)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	__be32 *p;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + length);
11462306a36Sopenharmony_ci	xdr_encode_opaque(p, data, length);
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int decode_netobj(struct xdr_stream *xdr,
11862306a36Sopenharmony_ci			 struct xdr_netobj *obj)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	ssize_t ret;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	ret = xdr_stream_decode_opaque_inline(xdr, (void *)&obj->data,
12362306a36Sopenharmony_ci						XDR_MAX_NETOBJ);
12462306a36Sopenharmony_ci	if (unlikely(ret < 0))
12562306a36Sopenharmony_ci		return -EIO;
12662306a36Sopenharmony_ci	obj->len = ret;
12762306a36Sopenharmony_ci	return 0;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/*
13162306a36Sopenharmony_ci *	netobj cookie;
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_cistatic void encode_cookie(struct xdr_stream *xdr,
13462306a36Sopenharmony_ci			  const struct nlm_cookie *cookie)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic int decode_cookie(struct xdr_stream *xdr,
14062306a36Sopenharmony_ci			     struct nlm_cookie *cookie)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	u32 length;
14362306a36Sopenharmony_ci	__be32 *p;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
14662306a36Sopenharmony_ci	if (unlikely(p == NULL))
14762306a36Sopenharmony_ci		goto out_overflow;
14862306a36Sopenharmony_ci	length = be32_to_cpup(p++);
14962306a36Sopenharmony_ci	/* apparently HPUX can return empty cookies */
15062306a36Sopenharmony_ci	if (length == 0)
15162306a36Sopenharmony_ci		goto out_hpux;
15262306a36Sopenharmony_ci	if (length > NLM_MAXCOOKIELEN)
15362306a36Sopenharmony_ci		goto out_size;
15462306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, length);
15562306a36Sopenharmony_ci	if (unlikely(p == NULL))
15662306a36Sopenharmony_ci		goto out_overflow;
15762306a36Sopenharmony_ci	cookie->len = length;
15862306a36Sopenharmony_ci	memcpy(cookie->data, p, length);
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ciout_hpux:
16162306a36Sopenharmony_ci	cookie->len = 4;
16262306a36Sopenharmony_ci	memset(cookie->data, 0, 4);
16362306a36Sopenharmony_ci	return 0;
16462306a36Sopenharmony_ciout_size:
16562306a36Sopenharmony_ci	dprintk("NFS: returned cookie was too long: %u\n", length);
16662306a36Sopenharmony_ci	return -EIO;
16762306a36Sopenharmony_ciout_overflow:
16862306a36Sopenharmony_ci	return -EIO;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/*
17262306a36Sopenharmony_ci *	netobj fh;
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_cistatic void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	encode_netobj(xdr, (u8 *)&fh->data, fh->size);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/*
18062306a36Sopenharmony_ci *	enum nlm4_stats {
18162306a36Sopenharmony_ci *		NLM4_GRANTED = 0,
18262306a36Sopenharmony_ci *		NLM4_DENIED = 1,
18362306a36Sopenharmony_ci *		NLM4_DENIED_NOLOCKS = 2,
18462306a36Sopenharmony_ci *		NLM4_BLOCKED = 3,
18562306a36Sopenharmony_ci *		NLM4_DENIED_GRACE_PERIOD = 4,
18662306a36Sopenharmony_ci *		NLM4_DEADLCK = 5,
18762306a36Sopenharmony_ci *		NLM4_ROFS = 6,
18862306a36Sopenharmony_ci *		NLM4_STALE_FH = 7,
18962306a36Sopenharmony_ci *		NLM4_FBIG = 8,
19062306a36Sopenharmony_ci *		NLM4_FAILED = 9
19162306a36Sopenharmony_ci *	};
19262306a36Sopenharmony_ci *
19362306a36Sopenharmony_ci *	struct nlm4_stat {
19462306a36Sopenharmony_ci *		nlm4_stats stat;
19562306a36Sopenharmony_ci *	};
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * NB: we don't swap bytes for the NLM status values.  The upper
19862306a36Sopenharmony_ci * layers deal directly with the status value in network byte
19962306a36Sopenharmony_ci * order.
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_cistatic void encode_nlm4_stat(struct xdr_stream *xdr,
20262306a36Sopenharmony_ci			     const __be32 stat)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	__be32 *p;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	BUG_ON(be32_to_cpu(stat) > NLM_FAILED);
20762306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
20862306a36Sopenharmony_ci	*p = stat;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	__be32 *p;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
21662306a36Sopenharmony_ci	if (unlikely(p == NULL))
21762306a36Sopenharmony_ci		goto out_overflow;
21862306a36Sopenharmony_ci	if (unlikely(ntohl(*p) > ntohl(nlm4_failed)))
21962306a36Sopenharmony_ci		goto out_bad_xdr;
22062306a36Sopenharmony_ci	*stat = *p;
22162306a36Sopenharmony_ci	return 0;
22262306a36Sopenharmony_ciout_bad_xdr:
22362306a36Sopenharmony_ci	dprintk("%s: server returned invalid nlm4_stats value: %u\n",
22462306a36Sopenharmony_ci			__func__, be32_to_cpup(p));
22562306a36Sopenharmony_ci	return -EIO;
22662306a36Sopenharmony_ciout_overflow:
22762306a36Sopenharmony_ci	return -EIO;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci/*
23162306a36Sopenharmony_ci *	struct nlm4_holder {
23262306a36Sopenharmony_ci *		bool	exclusive;
23362306a36Sopenharmony_ci *		int32	svid;
23462306a36Sopenharmony_ci *		netobj	oh;
23562306a36Sopenharmony_ci *		uint64	l_offset;
23662306a36Sopenharmony_ci *		uint64	l_len;
23762306a36Sopenharmony_ci *	};
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic void encode_nlm4_holder(struct xdr_stream *xdr,
24062306a36Sopenharmony_ci			       const struct nlm_res *result)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	const struct nlm_lock *lock = &result->lock;
24362306a36Sopenharmony_ci	u64 l_offset, l_len;
24462306a36Sopenharmony_ci	__be32 *p;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
24762306a36Sopenharmony_ci	encode_int32(xdr, lock->svid);
24862306a36Sopenharmony_ci	encode_netobj(xdr, lock->oh.data, lock->oh.len);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4);
25162306a36Sopenharmony_ci	nlm4_compute_offsets(lock, &l_offset, &l_len);
25262306a36Sopenharmony_ci	p = xdr_encode_hyper(p, l_offset);
25362306a36Sopenharmony_ci	xdr_encode_hyper(p, l_len);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct nlm_lock *lock = &result->lock;
25962306a36Sopenharmony_ci	struct file_lock *fl = &lock->fl;
26062306a36Sopenharmony_ci	u64 l_offset, l_len;
26162306a36Sopenharmony_ci	u32 exclusive;
26262306a36Sopenharmony_ci	int error;
26362306a36Sopenharmony_ci	__be32 *p;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	memset(lock, 0, sizeof(*lock));
26662306a36Sopenharmony_ci	locks_init_lock(fl);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 + 4);
26962306a36Sopenharmony_ci	if (unlikely(p == NULL))
27062306a36Sopenharmony_ci		goto out_overflow;
27162306a36Sopenharmony_ci	exclusive = be32_to_cpup(p++);
27262306a36Sopenharmony_ci	lock->svid = be32_to_cpup(p);
27362306a36Sopenharmony_ci	fl->fl_pid = (pid_t)lock->svid;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	error = decode_netobj(xdr, &lock->oh);
27662306a36Sopenharmony_ci	if (unlikely(error))
27762306a36Sopenharmony_ci		goto out;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 8 + 8);
28062306a36Sopenharmony_ci	if (unlikely(p == NULL))
28162306a36Sopenharmony_ci		goto out_overflow;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	fl->fl_flags = FL_POSIX;
28462306a36Sopenharmony_ci	fl->fl_type  = exclusive != 0 ? F_WRLCK : F_RDLCK;
28562306a36Sopenharmony_ci	p = xdr_decode_hyper(p, &l_offset);
28662306a36Sopenharmony_ci	xdr_decode_hyper(p, &l_len);
28762306a36Sopenharmony_ci	nlm4svc_set_file_lock_range(fl, l_offset, l_len);
28862306a36Sopenharmony_ci	error = 0;
28962306a36Sopenharmony_ciout:
29062306a36Sopenharmony_ci	return error;
29162306a36Sopenharmony_ciout_overflow:
29262306a36Sopenharmony_ci	return -EIO;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/*
29662306a36Sopenharmony_ci *	string caller_name<LM_MAXSTRLEN>;
29762306a36Sopenharmony_ci */
29862306a36Sopenharmony_cistatic void encode_caller_name(struct xdr_stream *xdr, const char *name)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	/* NB: client-side does not set lock->len */
30162306a36Sopenharmony_ci	u32 length = strlen(name);
30262306a36Sopenharmony_ci	__be32 *p;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + length);
30562306a36Sopenharmony_ci	xdr_encode_opaque(p, name, length);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/*
30962306a36Sopenharmony_ci *	struct nlm4_lock {
31062306a36Sopenharmony_ci *		string	caller_name<LM_MAXSTRLEN>;
31162306a36Sopenharmony_ci *		netobj	fh;
31262306a36Sopenharmony_ci *		netobj	oh;
31362306a36Sopenharmony_ci *		int32	svid;
31462306a36Sopenharmony_ci *		uint64	l_offset;
31562306a36Sopenharmony_ci *		uint64	l_len;
31662306a36Sopenharmony_ci *	};
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistatic void encode_nlm4_lock(struct xdr_stream *xdr,
31962306a36Sopenharmony_ci			     const struct nlm_lock *lock)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	u64 l_offset, l_len;
32262306a36Sopenharmony_ci	__be32 *p;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	encode_caller_name(xdr, lock->caller);
32562306a36Sopenharmony_ci	encode_fh(xdr, &lock->fh);
32662306a36Sopenharmony_ci	encode_netobj(xdr, lock->oh.data, lock->oh.len);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 8 + 8);
32962306a36Sopenharmony_ci	*p++ = cpu_to_be32(lock->svid);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	nlm4_compute_offsets(lock, &l_offset, &l_len);
33262306a36Sopenharmony_ci	p = xdr_encode_hyper(p, l_offset);
33362306a36Sopenharmony_ci	xdr_encode_hyper(p, l_len);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci/*
33862306a36Sopenharmony_ci * NLMv4 XDR encode functions
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci * NLMv4 argument types are defined in Appendix II of RFC 1813:
34162306a36Sopenharmony_ci * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's
34262306a36Sopenharmony_ci * "Protocols for Interworking: XNFS, Version 3W".
34362306a36Sopenharmony_ci */
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/*
34662306a36Sopenharmony_ci *	struct nlm4_testargs {
34762306a36Sopenharmony_ci *		netobj cookie;
34862306a36Sopenharmony_ci *		bool exclusive;
34962306a36Sopenharmony_ci *		struct nlm4_lock alock;
35062306a36Sopenharmony_ci *	};
35162306a36Sopenharmony_ci */
35262306a36Sopenharmony_cistatic void nlm4_xdr_enc_testargs(struct rpc_rqst *req,
35362306a36Sopenharmony_ci				  struct xdr_stream *xdr,
35462306a36Sopenharmony_ci				  const void *data)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	const struct nlm_args *args = data;
35762306a36Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
36062306a36Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
36162306a36Sopenharmony_ci	encode_nlm4_lock(xdr, lock);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/*
36562306a36Sopenharmony_ci *	struct nlm4_lockargs {
36662306a36Sopenharmony_ci *		netobj cookie;
36762306a36Sopenharmony_ci *		bool block;
36862306a36Sopenharmony_ci *		bool exclusive;
36962306a36Sopenharmony_ci *		struct nlm4_lock alock;
37062306a36Sopenharmony_ci *		bool reclaim;
37162306a36Sopenharmony_ci *		int state;
37262306a36Sopenharmony_ci *	};
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_cistatic void nlm4_xdr_enc_lockargs(struct rpc_rqst *req,
37562306a36Sopenharmony_ci				  struct xdr_stream *xdr,
37662306a36Sopenharmony_ci				  const void *data)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	const struct nlm_args *args = data;
37962306a36Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
38262306a36Sopenharmony_ci	encode_bool(xdr, args->block);
38362306a36Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
38462306a36Sopenharmony_ci	encode_nlm4_lock(xdr, lock);
38562306a36Sopenharmony_ci	encode_bool(xdr, args->reclaim);
38662306a36Sopenharmony_ci	encode_int32(xdr, args->state);
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/*
39062306a36Sopenharmony_ci *	struct nlm4_cancargs {
39162306a36Sopenharmony_ci *		netobj cookie;
39262306a36Sopenharmony_ci *		bool block;
39362306a36Sopenharmony_ci *		bool exclusive;
39462306a36Sopenharmony_ci *		struct nlm4_lock alock;
39562306a36Sopenharmony_ci *	};
39662306a36Sopenharmony_ci */
39762306a36Sopenharmony_cistatic void nlm4_xdr_enc_cancargs(struct rpc_rqst *req,
39862306a36Sopenharmony_ci				  struct xdr_stream *xdr,
39962306a36Sopenharmony_ci				  const void *data)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	const struct nlm_args *args = data;
40262306a36Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
40562306a36Sopenharmony_ci	encode_bool(xdr, args->block);
40662306a36Sopenharmony_ci	encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
40762306a36Sopenharmony_ci	encode_nlm4_lock(xdr, lock);
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/*
41162306a36Sopenharmony_ci *	struct nlm4_unlockargs {
41262306a36Sopenharmony_ci *		netobj cookie;
41362306a36Sopenharmony_ci *		struct nlm4_lock alock;
41462306a36Sopenharmony_ci *	};
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistatic void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req,
41762306a36Sopenharmony_ci				    struct xdr_stream *xdr,
41862306a36Sopenharmony_ci				    const void *data)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	const struct nlm_args *args = data;
42162306a36Sopenharmony_ci	const struct nlm_lock *lock = &args->lock;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	encode_cookie(xdr, &args->cookie);
42462306a36Sopenharmony_ci	encode_nlm4_lock(xdr, lock);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci *	struct nlm4_res {
42962306a36Sopenharmony_ci *		netobj cookie;
43062306a36Sopenharmony_ci *		nlm4_stat stat;
43162306a36Sopenharmony_ci *	};
43262306a36Sopenharmony_ci */
43362306a36Sopenharmony_cistatic void nlm4_xdr_enc_res(struct rpc_rqst *req,
43462306a36Sopenharmony_ci			     struct xdr_stream *xdr,
43562306a36Sopenharmony_ci			     const void *data)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	const struct nlm_res *result = data;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	encode_cookie(xdr, &result->cookie);
44062306a36Sopenharmony_ci	encode_nlm4_stat(xdr, result->status);
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/*
44462306a36Sopenharmony_ci *	union nlm4_testrply switch (nlm4_stats stat) {
44562306a36Sopenharmony_ci *	case NLM4_DENIED:
44662306a36Sopenharmony_ci *		struct nlm4_holder holder;
44762306a36Sopenharmony_ci *	default:
44862306a36Sopenharmony_ci *		void;
44962306a36Sopenharmony_ci *	};
45062306a36Sopenharmony_ci *
45162306a36Sopenharmony_ci *	struct nlm4_testres {
45262306a36Sopenharmony_ci *		netobj cookie;
45362306a36Sopenharmony_ci *		nlm4_testrply test_stat;
45462306a36Sopenharmony_ci *	};
45562306a36Sopenharmony_ci */
45662306a36Sopenharmony_cistatic void nlm4_xdr_enc_testres(struct rpc_rqst *req,
45762306a36Sopenharmony_ci				 struct xdr_stream *xdr,
45862306a36Sopenharmony_ci				 const void *data)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	const struct nlm_res *result = data;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	encode_cookie(xdr, &result->cookie);
46362306a36Sopenharmony_ci	encode_nlm4_stat(xdr, result->status);
46462306a36Sopenharmony_ci	if (result->status == nlm_lck_denied)
46562306a36Sopenharmony_ci		encode_nlm4_holder(xdr, result);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/*
47062306a36Sopenharmony_ci * NLMv4 XDR decode functions
47162306a36Sopenharmony_ci *
47262306a36Sopenharmony_ci * NLMv4 argument types are defined in Appendix II of RFC 1813:
47362306a36Sopenharmony_ci * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's
47462306a36Sopenharmony_ci * "Protocols for Interworking: XNFS, Version 3W".
47562306a36Sopenharmony_ci */
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci/*
47862306a36Sopenharmony_ci *	union nlm4_testrply switch (nlm4_stats stat) {
47962306a36Sopenharmony_ci *	case NLM4_DENIED:
48062306a36Sopenharmony_ci *		struct nlm4_holder holder;
48162306a36Sopenharmony_ci *	default:
48262306a36Sopenharmony_ci *		void;
48362306a36Sopenharmony_ci *	};
48462306a36Sopenharmony_ci *
48562306a36Sopenharmony_ci *	struct nlm4_testres {
48662306a36Sopenharmony_ci *		netobj cookie;
48762306a36Sopenharmony_ci *		nlm4_testrply test_stat;
48862306a36Sopenharmony_ci *	};
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic int decode_nlm4_testrply(struct xdr_stream *xdr,
49162306a36Sopenharmony_ci				struct nlm_res *result)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	int error;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	error = decode_nlm4_stat(xdr, &result->status);
49662306a36Sopenharmony_ci	if (unlikely(error))
49762306a36Sopenharmony_ci		goto out;
49862306a36Sopenharmony_ci	if (result->status == nlm_lck_denied)
49962306a36Sopenharmony_ci		error = decode_nlm4_holder(xdr, result);
50062306a36Sopenharmony_ciout:
50162306a36Sopenharmony_ci	return error;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int nlm4_xdr_dec_testres(struct rpc_rqst *req,
50562306a36Sopenharmony_ci				struct xdr_stream *xdr,
50662306a36Sopenharmony_ci				void *data)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct nlm_res *result = data;
50962306a36Sopenharmony_ci	int error;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	error = decode_cookie(xdr, &result->cookie);
51262306a36Sopenharmony_ci	if (unlikely(error))
51362306a36Sopenharmony_ci		goto out;
51462306a36Sopenharmony_ci	error = decode_nlm4_testrply(xdr, result);
51562306a36Sopenharmony_ciout:
51662306a36Sopenharmony_ci	return error;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci/*
52062306a36Sopenharmony_ci *	struct nlm4_res {
52162306a36Sopenharmony_ci *		netobj cookie;
52262306a36Sopenharmony_ci *		nlm4_stat stat;
52362306a36Sopenharmony_ci *	};
52462306a36Sopenharmony_ci */
52562306a36Sopenharmony_cistatic int nlm4_xdr_dec_res(struct rpc_rqst *req,
52662306a36Sopenharmony_ci			    struct xdr_stream *xdr,
52762306a36Sopenharmony_ci			    void *data)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct nlm_res *result = data;
53062306a36Sopenharmony_ci	int error;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	error = decode_cookie(xdr, &result->cookie);
53362306a36Sopenharmony_ci	if (unlikely(error))
53462306a36Sopenharmony_ci		goto out;
53562306a36Sopenharmony_ci	error = decode_nlm4_stat(xdr, &result->status);
53662306a36Sopenharmony_ciout:
53762306a36Sopenharmony_ci	return error;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/*
54262306a36Sopenharmony_ci * For NLM, a void procedure really returns nothing
54362306a36Sopenharmony_ci */
54462306a36Sopenharmony_ci#define nlm4_xdr_dec_norep	NULL
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci#define PROC(proc, argtype, restype)					\
54762306a36Sopenharmony_ci[NLMPROC_##proc] = {							\
54862306a36Sopenharmony_ci	.p_proc      = NLMPROC_##proc,					\
54962306a36Sopenharmony_ci	.p_encode    = nlm4_xdr_enc_##argtype,				\
55062306a36Sopenharmony_ci	.p_decode    = nlm4_xdr_dec_##restype,				\
55162306a36Sopenharmony_ci	.p_arglen    = NLM4_##argtype##_sz,				\
55262306a36Sopenharmony_ci	.p_replen    = NLM4_##restype##_sz,				\
55362306a36Sopenharmony_ci	.p_statidx   = NLMPROC_##proc,					\
55462306a36Sopenharmony_ci	.p_name      = #proc,						\
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic const struct rpc_procinfo nlm4_procedures[] = {
55862306a36Sopenharmony_ci	PROC(TEST,		testargs,	testres),
55962306a36Sopenharmony_ci	PROC(LOCK,		lockargs,	res),
56062306a36Sopenharmony_ci	PROC(CANCEL,		cancargs,	res),
56162306a36Sopenharmony_ci	PROC(UNLOCK,		unlockargs,	res),
56262306a36Sopenharmony_ci	PROC(GRANTED,		testargs,	res),
56362306a36Sopenharmony_ci	PROC(TEST_MSG,		testargs,	norep),
56462306a36Sopenharmony_ci	PROC(LOCK_MSG,		lockargs,	norep),
56562306a36Sopenharmony_ci	PROC(CANCEL_MSG,	cancargs,	norep),
56662306a36Sopenharmony_ci	PROC(UNLOCK_MSG,	unlockargs,	norep),
56762306a36Sopenharmony_ci	PROC(GRANTED_MSG,	testargs,	norep),
56862306a36Sopenharmony_ci	PROC(TEST_RES,		testres,	norep),
56962306a36Sopenharmony_ci	PROC(LOCK_RES,		res,		norep),
57062306a36Sopenharmony_ci	PROC(CANCEL_RES,	res,		norep),
57162306a36Sopenharmony_ci	PROC(UNLOCK_RES,	res,		norep),
57262306a36Sopenharmony_ci	PROC(GRANTED_RES,	res,		norep),
57362306a36Sopenharmony_ci};
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic unsigned int nlm_version4_counts[ARRAY_SIZE(nlm4_procedures)];
57662306a36Sopenharmony_ciconst struct rpc_version nlm_version4 = {
57762306a36Sopenharmony_ci	.number		= 4,
57862306a36Sopenharmony_ci	.nrprocs	= ARRAY_SIZE(nlm4_procedures),
57962306a36Sopenharmony_ci	.procs		= nlm4_procedures,
58062306a36Sopenharmony_ci	.counts		= nlm_version4_counts,
58162306a36Sopenharmony_ci};
582