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