xref: /openbmc/linux/fs/lockd/xdr4.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/fs/lockd/xdr4.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * XDR support for lockd and the lock client.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
81da177e4SLinus Torvalds  * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include <linux/types.h>
121da177e4SLinus Torvalds #include <linux/sched.h>
131da177e4SLinus Torvalds #include <linux/nfs.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/sunrpc/xdr.h>
161da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
171da177e4SLinus Torvalds #include <linux/sunrpc/svc.h>
181da177e4SLinus Torvalds #include <linux/sunrpc/stats.h>
191da177e4SLinus Torvalds #include <linux/lockd/lockd.h>
201da177e4SLinus Torvalds 
217956521aSChuck Lever #include "svcxdr.h"
227956521aSChuck Lever 
231da177e4SLinus Torvalds static inline s64
loff_t_to_s64(loff_t offset)241da177e4SLinus Torvalds loff_t_to_s64(loff_t offset)
251da177e4SLinus Torvalds {
261da177e4SLinus Torvalds 	s64 res;
271da177e4SLinus Torvalds 	if (offset > NLM4_OFFSET_MAX)
281da177e4SLinus Torvalds 		res = NLM4_OFFSET_MAX;
291da177e4SLinus Torvalds 	else if (offset < -NLM4_OFFSET_MAX)
301da177e4SLinus Torvalds 		res = -NLM4_OFFSET_MAX;
311da177e4SLinus Torvalds 	else
321da177e4SLinus Torvalds 		res = offset;
331da177e4SLinus Torvalds 	return res;
341da177e4SLinus Torvalds }
351da177e4SLinus Torvalds 
nlm4svc_set_file_lock_range(struct file_lock * fl,u64 off,u64 len)36*7ff84910SJeff Layton void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len)
37*7ff84910SJeff Layton {
38*7ff84910SJeff Layton 	s64 end = off + len - 1;
39*7ff84910SJeff Layton 
40*7ff84910SJeff Layton 	fl->fl_start = off;
41*7ff84910SJeff Layton 	if (len == 0 || end < 0)
42*7ff84910SJeff Layton 		fl->fl_end = OFFSET_MAX;
43*7ff84910SJeff Layton 	else
44*7ff84910SJeff Layton 		fl->fl_end = end;
45*7ff84910SJeff Layton }
46*7ff84910SJeff Layton 
471da177e4SLinus Torvalds /*
48345b4159SChuck Lever  * NLM file handles are defined by specification to be a variable-length
49345b4159SChuck Lever  * XDR opaque no longer than 1024 bytes. However, this implementation
50345b4159SChuck Lever  * limits their length to the size of an NFSv3 file handle.
51345b4159SChuck Lever  */
52345b4159SChuck Lever static bool
svcxdr_decode_fhandle(struct xdr_stream * xdr,struct nfs_fh * fh)53345b4159SChuck Lever svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
54345b4159SChuck Lever {
55345b4159SChuck Lever 	__be32 *p;
56345b4159SChuck Lever 	u32 len;
57345b4159SChuck Lever 
58345b4159SChuck Lever 	if (xdr_stream_decode_u32(xdr, &len) < 0)
59345b4159SChuck Lever 		return false;
60345b4159SChuck Lever 	if (len > NFS_MAXFHSIZE)
61345b4159SChuck Lever 		return false;
62345b4159SChuck Lever 
63345b4159SChuck Lever 	p = xdr_inline_decode(xdr, len);
64345b4159SChuck Lever 	if (!p)
65345b4159SChuck Lever 		return false;
66345b4159SChuck Lever 	fh->size = len;
67345b4159SChuck Lever 	memcpy(fh->data, p, len);
68345b4159SChuck Lever 	memset(fh->data + len, 0, sizeof(fh->data) - len);
69345b4159SChuck Lever 
70345b4159SChuck Lever 	return true;
71345b4159SChuck Lever }
72345b4159SChuck Lever 
73345b4159SChuck Lever static bool
svcxdr_decode_lock(struct xdr_stream * xdr,struct nlm_lock * lock)74345b4159SChuck Lever svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
75345b4159SChuck Lever {
76345b4159SChuck Lever 	struct file_lock *fl = &lock->fl;
77345b4159SChuck Lever 
78345b4159SChuck Lever 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
79345b4159SChuck Lever 		return false;
80345b4159SChuck Lever 	if (!svcxdr_decode_fhandle(xdr, &lock->fh))
81345b4159SChuck Lever 		return false;
82345b4159SChuck Lever 	if (!svcxdr_decode_owner(xdr, &lock->oh))
83345b4159SChuck Lever 		return false;
84345b4159SChuck Lever 	if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
85345b4159SChuck Lever 		return false;
866930bcbfSJeff Layton 	if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0)
87345b4159SChuck Lever 		return false;
886930bcbfSJeff Layton 	if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0)
89345b4159SChuck Lever 		return false;
90345b4159SChuck Lever 
91345b4159SChuck Lever 	locks_init_lock(fl);
92345b4159SChuck Lever 	fl->fl_flags = FL_POSIX;
93345b4159SChuck Lever 	fl->fl_type  = F_RDLCK;
94*7ff84910SJeff Layton 	nlm4svc_set_file_lock_range(fl, lock->lock_start, lock->lock_len);
95345b4159SChuck Lever 	return true;
96345b4159SChuck Lever }
97345b4159SChuck Lever 
981beef147SChuck Lever static bool
svcxdr_encode_holder(struct xdr_stream * xdr,const struct nlm_lock * lock)991beef147SChuck Lever svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
1001da177e4SLinus Torvalds {
1011beef147SChuck Lever 	const struct file_lock *fl = &lock->fl;
1021da177e4SLinus Torvalds 	s64 start, len;
1031da177e4SLinus Torvalds 
1041beef147SChuck Lever 	/* exclusive */
1051beef147SChuck Lever 	if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
1061beef147SChuck Lever 		return false;
1071beef147SChuck Lever 	if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
1081beef147SChuck Lever 		return false;
1091beef147SChuck Lever 	if (!svcxdr_encode_owner(xdr, &lock->oh))
1101beef147SChuck Lever 		return false;
1111da177e4SLinus Torvalds 	start = loff_t_to_s64(fl->fl_start);
1121da177e4SLinus Torvalds 	if (fl->fl_end == OFFSET_MAX)
1131da177e4SLinus Torvalds 		len = 0;
1141da177e4SLinus Torvalds 	else
1151da177e4SLinus Torvalds 		len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
1161beef147SChuck Lever 	if (xdr_stream_encode_u64(xdr, start) < 0)
1171beef147SChuck Lever 		return false;
1181beef147SChuck Lever 	if (xdr_stream_encode_u64(xdr, len) < 0)
1191beef147SChuck Lever 		return false;
1201da177e4SLinus Torvalds 
1211beef147SChuck Lever 	return true;
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds 
1241beef147SChuck Lever static bool
svcxdr_encode_testrply(struct xdr_stream * xdr,const struct nlm_res * resp)1251beef147SChuck Lever svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
1261beef147SChuck Lever {
1271beef147SChuck Lever 	if (!svcxdr_encode_stats(xdr, resp->status))
1281beef147SChuck Lever 		return false;
1291beef147SChuck Lever 	switch (resp->status) {
1301beef147SChuck Lever 	case nlm_lck_denied:
1311beef147SChuck Lever 		if (!svcxdr_encode_holder(xdr, &resp->lock))
1321beef147SChuck Lever 			return false;
1331beef147SChuck Lever 	}
1341beef147SChuck Lever 
1351beef147SChuck Lever 	return true;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds /*
1407956521aSChuck Lever  * Decode Call arguments
1411da177e4SLinus Torvalds  */
1427956521aSChuck Lever 
143c44b31c2SChuck Lever bool
nlm4svc_decode_void(struct svc_rqst * rqstp,struct xdr_stream * xdr)14416c66364SChuck Lever nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1457956521aSChuck Lever {
146c44b31c2SChuck Lever 	return true;
1477956521aSChuck Lever }
1487956521aSChuck Lever 
149c44b31c2SChuck Lever bool
nlm4svc_decode_testargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)15016c66364SChuck Lever nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1511da177e4SLinus Torvalds {
152026fec7eSChristoph Hellwig 	struct nlm_args *argp = rqstp->rq_argp;
1531da177e4SLinus Torvalds 	u32 exclusive;
1541da177e4SLinus Torvalds 
155345b4159SChuck Lever 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
156c44b31c2SChuck Lever 		return false;
157345b4159SChuck Lever 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
158c44b31c2SChuck Lever 		return false;
159345b4159SChuck Lever 	if (!svcxdr_decode_lock(xdr, &argp->lock))
160c44b31c2SChuck Lever 		return false;
1611da177e4SLinus Torvalds 	if (exclusive)
1621da177e4SLinus Torvalds 		argp->lock.fl.fl_type = F_WRLCK;
1631da177e4SLinus Torvalds 
164c44b31c2SChuck Lever 	return true;
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds 
167c44b31c2SChuck Lever bool
nlm4svc_decode_lockargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)16816c66364SChuck Lever nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1690e5977afSChuck Lever {
1700e5977afSChuck Lever 	struct nlm_args *argp = rqstp->rq_argp;
1710e5977afSChuck Lever 	u32 exclusive;
1720e5977afSChuck Lever 
1730e5977afSChuck Lever 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
174c44b31c2SChuck Lever 		return false;
1750e5977afSChuck Lever 	if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
176c44b31c2SChuck Lever 		return false;
1770e5977afSChuck Lever 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
178c44b31c2SChuck Lever 		return false;
1790e5977afSChuck Lever 	if (!svcxdr_decode_lock(xdr, &argp->lock))
180c44b31c2SChuck Lever 		return false;
1810e5977afSChuck Lever 	if (exclusive)
1820e5977afSChuck Lever 		argp->lock.fl.fl_type = F_WRLCK;
1830e5977afSChuck Lever 	if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
184c44b31c2SChuck Lever 		return false;
1850e5977afSChuck Lever 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
186c44b31c2SChuck Lever 		return false;
1870e5977afSChuck Lever 	argp->monitor = 1;		/* monitor client by default */
1880e5977afSChuck Lever 
189c44b31c2SChuck Lever 	return true;
1900e5977afSChuck Lever }
1910e5977afSChuck Lever 
192c44b31c2SChuck Lever bool
nlm4svc_decode_cancargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)19316c66364SChuck Lever nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1941e1f38dcSChuck Lever {
1951e1f38dcSChuck Lever 	struct nlm_args *argp = rqstp->rq_argp;
1961e1f38dcSChuck Lever 	u32 exclusive;
1971e1f38dcSChuck Lever 
1981e1f38dcSChuck Lever 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
199c44b31c2SChuck Lever 		return false;
2001e1f38dcSChuck Lever 	if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
201c44b31c2SChuck Lever 		return false;
2021e1f38dcSChuck Lever 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
203c44b31c2SChuck Lever 		return false;
2041e1f38dcSChuck Lever 	if (!svcxdr_decode_lock(xdr, &argp->lock))
205c44b31c2SChuck Lever 		return false;
2061e1f38dcSChuck Lever 	if (exclusive)
2071e1f38dcSChuck Lever 		argp->lock.fl.fl_type = F_WRLCK;
208c44b31c2SChuck Lever 
209c44b31c2SChuck Lever 	return true;
2101e1f38dcSChuck Lever }
2111e1f38dcSChuck Lever 
212c44b31c2SChuck Lever bool
nlm4svc_decode_unlockargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)21316c66364SChuck Lever nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
214d76d8c25SChuck Lever {
215d76d8c25SChuck Lever 	struct nlm_args *argp = rqstp->rq_argp;
216d76d8c25SChuck Lever 
217d76d8c25SChuck Lever 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
218c44b31c2SChuck Lever 		return false;
219d76d8c25SChuck Lever 	if (!svcxdr_decode_lock(xdr, &argp->lock))
220c44b31c2SChuck Lever 		return false;
221d76d8c25SChuck Lever 	argp->lock.fl.fl_type = F_UNLCK;
222d76d8c25SChuck Lever 
223c44b31c2SChuck Lever 	return true;
224d76d8c25SChuck Lever }
225d76d8c25SChuck Lever 
226c44b31c2SChuck Lever bool
nlm4svc_decode_res(struct svc_rqst * rqstp,struct xdr_stream * xdr)22716c66364SChuck Lever nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
228b4c24b5aSChuck Lever {
229b4c24b5aSChuck Lever 	struct nlm_res *resp = rqstp->rq_argp;
230b4c24b5aSChuck Lever 
231b4c24b5aSChuck Lever 	if (!svcxdr_decode_cookie(xdr, &resp->cookie))
232c44b31c2SChuck Lever 		return false;
233b4c24b5aSChuck Lever 	if (!svcxdr_decode_stats(xdr, &resp->status))
234c44b31c2SChuck Lever 		return false;
235b4c24b5aSChuck Lever 
236c44b31c2SChuck Lever 	return true;
237b4c24b5aSChuck Lever }
238b4c24b5aSChuck Lever 
239c44b31c2SChuck Lever bool
nlm4svc_decode_reboot(struct svc_rqst * rqstp,struct xdr_stream * xdr)24016c66364SChuck Lever nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr)
241bc3665fdSChuck Lever {
242bc3665fdSChuck Lever 	struct nlm_reboot *argp = rqstp->rq_argp;
24316c66364SChuck Lever 	__be32 *p;
244bc3665fdSChuck Lever 	u32 len;
245bc3665fdSChuck Lever 
246bc3665fdSChuck Lever 	if (xdr_stream_decode_u32(xdr, &len) < 0)
247c44b31c2SChuck Lever 		return false;
248bc3665fdSChuck Lever 	if (len > SM_MAXSTRLEN)
249c44b31c2SChuck Lever 		return false;
250bc3665fdSChuck Lever 	p = xdr_inline_decode(xdr, len);
251bc3665fdSChuck Lever 	if (!p)
252c44b31c2SChuck Lever 		return false;
253bc3665fdSChuck Lever 	argp->len = len;
254bc3665fdSChuck Lever 	argp->mon = (char *)p;
255bc3665fdSChuck Lever 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
256c44b31c2SChuck Lever 		return false;
257bc3665fdSChuck Lever 	p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
258bc3665fdSChuck Lever 	if (!p)
259c44b31c2SChuck Lever 		return false;
260bc3665fdSChuck Lever 	memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
261bc3665fdSChuck Lever 
262c44b31c2SChuck Lever 	return true;
263bc3665fdSChuck Lever }
264bc3665fdSChuck Lever 
265c44b31c2SChuck Lever bool
nlm4svc_decode_shareargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)26616c66364SChuck Lever nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
2671da177e4SLinus Torvalds {
268026fec7eSChristoph Hellwig 	struct nlm_args *argp = rqstp->rq_argp;
2691da177e4SLinus Torvalds 	struct nlm_lock	*lock = &argp->lock;
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	memset(lock, 0, sizeof(*lock));
2721da177e4SLinus Torvalds 	locks_init_lock(&lock->fl);
2737bab377fSTrond Myklebust 	lock->svid = ~(u32)0;
2741da177e4SLinus Torvalds 
2757cf96b6dSChuck Lever 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
276c44b31c2SChuck Lever 		return false;
2777cf96b6dSChuck Lever 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
278c44b31c2SChuck Lever 		return false;
2797cf96b6dSChuck Lever 	if (!svcxdr_decode_fhandle(xdr, &lock->fh))
280c44b31c2SChuck Lever 		return false;
2817cf96b6dSChuck Lever 	if (!svcxdr_decode_owner(xdr, &lock->oh))
282c44b31c2SChuck Lever 		return false;
2837cf96b6dSChuck Lever 	/* XXX: Range checks are missing in the original code */
2847cf96b6dSChuck Lever 	if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
285c44b31c2SChuck Lever 		return false;
2867cf96b6dSChuck Lever 	if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
287c44b31c2SChuck Lever 		return false;
2887cf96b6dSChuck Lever 
289c44b31c2SChuck Lever 	return true;
2907cf96b6dSChuck Lever }
2917cf96b6dSChuck Lever 
292c44b31c2SChuck Lever bool
nlm4svc_decode_notify(struct svc_rqst * rqstp,struct xdr_stream * xdr)29316c66364SChuck Lever nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr)
2943049e974SChuck Lever {
2953049e974SChuck Lever 	struct nlm_args *argp = rqstp->rq_argp;
2963049e974SChuck Lever 	struct nlm_lock	*lock = &argp->lock;
2973049e974SChuck Lever 
2983049e974SChuck Lever 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
299c44b31c2SChuck Lever 		return false;
3003049e974SChuck Lever 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
301c44b31c2SChuck Lever 		return false;
3023049e974SChuck Lever 
303c44b31c2SChuck Lever 	return true;
3043049e974SChuck Lever }
3053049e974SChuck Lever 
306ec757e42SChuck Lever 
307ec757e42SChuck Lever /*
308ec757e42SChuck Lever  * Encode Reply results
309ec757e42SChuck Lever  */
310ec757e42SChuck Lever 
311130e2054SChuck Lever bool
nlm4svc_encode_void(struct svc_rqst * rqstp,struct xdr_stream * xdr)312fda49441SChuck Lever nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
313ec757e42SChuck Lever {
314130e2054SChuck Lever 	return true;
315ec757e42SChuck Lever }
316ec757e42SChuck Lever 
317130e2054SChuck Lever bool
nlm4svc_encode_testres(struct svc_rqst * rqstp,struct xdr_stream * xdr)318fda49441SChuck Lever nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
3197cf96b6dSChuck Lever {
3207cf96b6dSChuck Lever 	struct nlm_res *resp = rqstp->rq_resp;
3217cf96b6dSChuck Lever 
3221beef147SChuck Lever 	return svcxdr_encode_cookie(xdr, &resp->cookie) &&
3231beef147SChuck Lever 		svcxdr_encode_testrply(xdr, resp);
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds 
326130e2054SChuck Lever bool
nlm4svc_encode_res(struct svc_rqst * rqstp,struct xdr_stream * xdr)327fda49441SChuck Lever nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
328447c14d4SChuck Lever {
329447c14d4SChuck Lever 	struct nlm_res *resp = rqstp->rq_resp;
330447c14d4SChuck Lever 
331447c14d4SChuck Lever 	return svcxdr_encode_cookie(xdr, &resp->cookie) &&
332447c14d4SChuck Lever 		svcxdr_encode_stats(xdr, resp->status);
333447c14d4SChuck Lever }
334447c14d4SChuck Lever 
335130e2054SChuck Lever bool
nlm4svc_encode_shareres(struct svc_rqst * rqstp,struct xdr_stream * xdr)336fda49441SChuck Lever nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
3371da177e4SLinus Torvalds {
33863f8de37SChristoph Hellwig 	struct nlm_res *resp = rqstp->rq_resp;
33963f8de37SChristoph Hellwig 
3400ff5b50aSChuck Lever 	if (!svcxdr_encode_cookie(xdr, &resp->cookie))
341130e2054SChuck Lever 		return false;
3420ff5b50aSChuck Lever 	if (!svcxdr_encode_stats(xdr, resp->status))
343130e2054SChuck Lever 		return false;
3440ff5b50aSChuck Lever 	/* sequence */
3450ff5b50aSChuck Lever 	if (xdr_stream_encode_u32(xdr, 0) < 0)
346130e2054SChuck Lever 		return false;
3470ff5b50aSChuck Lever 
348130e2054SChuck Lever 	return true;
3491da177e4SLinus Torvalds }
350