1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/lockd/xdr.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 */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <linux/types.h>
111da177e4SLinus Torvalds #include <linux/sched.h>
121da177e4SLinus Torvalds #include <linux/nfs.h>
131da177e4SLinus Torvalds
141da177e4SLinus Torvalds #include <linux/sunrpc/xdr.h>
151da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
161da177e4SLinus Torvalds #include <linux/sunrpc/svc.h>
171da177e4SLinus Torvalds #include <linux/sunrpc/stats.h>
181da177e4SLinus Torvalds #include <linux/lockd/lockd.h>
191da177e4SLinus Torvalds
209c69de4cSChristoph Hellwig #include <uapi/linux/nfs2.h>
219c69de4cSChristoph Hellwig
22cc1029b5SChuck Lever #include "svcxdr.h"
23cc1029b5SChuck Lever
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds static inline loff_t
s32_to_loff_t(__s32 offset)261da177e4SLinus Torvalds s32_to_loff_t(__s32 offset)
271da177e4SLinus Torvalds {
281da177e4SLinus Torvalds return (loff_t)offset;
291da177e4SLinus Torvalds }
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds static inline __s32
loff_t_to_s32(loff_t offset)321da177e4SLinus Torvalds loff_t_to_s32(loff_t offset)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds __s32 res;
351da177e4SLinus Torvalds if (offset >= NLM_OFFSET_MAX)
361da177e4SLinus Torvalds res = NLM_OFFSET_MAX;
371da177e4SLinus Torvalds else if (offset <= -NLM_OFFSET_MAX)
381da177e4SLinus Torvalds res = -NLM_OFFSET_MAX;
391da177e4SLinus Torvalds else
401da177e4SLinus Torvalds res = offset;
411da177e4SLinus Torvalds return res;
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds /*
452fd0c67aSChuck Lever * NLM file handles are defined by specification to be a variable-length
462fd0c67aSChuck Lever * XDR opaque no longer than 1024 bytes. However, this implementation
472fd0c67aSChuck Lever * constrains their length to exactly the length of an NFSv2 file
482fd0c67aSChuck Lever * handle.
492fd0c67aSChuck Lever */
502fd0c67aSChuck Lever static bool
svcxdr_decode_fhandle(struct xdr_stream * xdr,struct nfs_fh * fh)512fd0c67aSChuck Lever svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
522fd0c67aSChuck Lever {
532fd0c67aSChuck Lever __be32 *p;
542fd0c67aSChuck Lever u32 len;
552fd0c67aSChuck Lever
562fd0c67aSChuck Lever if (xdr_stream_decode_u32(xdr, &len) < 0)
572fd0c67aSChuck Lever return false;
582fd0c67aSChuck Lever if (len != NFS2_FHSIZE)
592fd0c67aSChuck Lever return false;
602fd0c67aSChuck Lever
612fd0c67aSChuck Lever p = xdr_inline_decode(xdr, len);
622fd0c67aSChuck Lever if (!p)
632fd0c67aSChuck Lever return false;
642fd0c67aSChuck Lever fh->size = NFS2_FHSIZE;
652fd0c67aSChuck Lever memcpy(fh->data, p, len);
662fd0c67aSChuck Lever memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
672fd0c67aSChuck Lever
682fd0c67aSChuck Lever return true;
692fd0c67aSChuck Lever }
702fd0c67aSChuck Lever
712fd0c67aSChuck Lever static bool
svcxdr_decode_lock(struct xdr_stream * xdr,struct nlm_lock * lock)722fd0c67aSChuck Lever svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
732fd0c67aSChuck Lever {
742fd0c67aSChuck Lever struct file_lock *fl = &lock->fl;
752fd0c67aSChuck Lever s32 start, len, end;
762fd0c67aSChuck Lever
772fd0c67aSChuck Lever if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
782fd0c67aSChuck Lever return false;
792fd0c67aSChuck Lever if (!svcxdr_decode_fhandle(xdr, &lock->fh))
802fd0c67aSChuck Lever return false;
812fd0c67aSChuck Lever if (!svcxdr_decode_owner(xdr, &lock->oh))
822fd0c67aSChuck Lever return false;
832fd0c67aSChuck Lever if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
842fd0c67aSChuck Lever return false;
852fd0c67aSChuck Lever if (xdr_stream_decode_u32(xdr, &start) < 0)
862fd0c67aSChuck Lever return false;
872fd0c67aSChuck Lever if (xdr_stream_decode_u32(xdr, &len) < 0)
882fd0c67aSChuck Lever return false;
892fd0c67aSChuck Lever
902fd0c67aSChuck Lever locks_init_lock(fl);
912fd0c67aSChuck Lever fl->fl_flags = FL_POSIX;
922fd0c67aSChuck Lever fl->fl_type = F_RDLCK;
932fd0c67aSChuck Lever end = start + len - 1;
942fd0c67aSChuck Lever fl->fl_start = s32_to_loff_t(start);
952fd0c67aSChuck Lever if (len == 0 || end < 0)
962fd0c67aSChuck Lever fl->fl_end = OFFSET_MAX;
972fd0c67aSChuck Lever else
982fd0c67aSChuck Lever fl->fl_end = s32_to_loff_t(end);
992fd0c67aSChuck Lever
1002fd0c67aSChuck Lever return true;
1012fd0c67aSChuck Lever }
1022fd0c67aSChuck Lever
103adf98a48SChuck Lever static bool
svcxdr_encode_holder(struct xdr_stream * xdr,const struct nlm_lock * lock)104adf98a48SChuck Lever svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
1051da177e4SLinus Torvalds {
106adf98a48SChuck Lever const struct file_lock *fl = &lock->fl;
1071da177e4SLinus Torvalds s32 start, len;
1081da177e4SLinus Torvalds
109adf98a48SChuck Lever /* exclusive */
110adf98a48SChuck Lever if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
111adf98a48SChuck Lever return false;
112adf98a48SChuck Lever if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
113adf98a48SChuck Lever return false;
114adf98a48SChuck Lever if (!svcxdr_encode_owner(xdr, &lock->oh))
115adf98a48SChuck Lever return false;
1161da177e4SLinus Torvalds start = loff_t_to_s32(fl->fl_start);
1171da177e4SLinus Torvalds if (fl->fl_end == OFFSET_MAX)
1181da177e4SLinus Torvalds len = 0;
1191da177e4SLinus Torvalds else
1201da177e4SLinus Torvalds len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
121adf98a48SChuck Lever if (xdr_stream_encode_u32(xdr, start) < 0)
122adf98a48SChuck Lever return false;
123adf98a48SChuck Lever if (xdr_stream_encode_u32(xdr, len) < 0)
124adf98a48SChuck Lever return false;
1251da177e4SLinus Torvalds
126adf98a48SChuck Lever return true;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds
129adf98a48SChuck Lever static bool
svcxdr_encode_testrply(struct xdr_stream * xdr,const struct nlm_res * resp)130adf98a48SChuck Lever svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
131adf98a48SChuck Lever {
132adf98a48SChuck Lever if (!svcxdr_encode_stats(xdr, resp->status))
133adf98a48SChuck Lever return false;
134adf98a48SChuck Lever switch (resp->status) {
135adf98a48SChuck Lever case nlm_lck_denied:
136adf98a48SChuck Lever if (!svcxdr_encode_holder(xdr, &resp->lock))
137adf98a48SChuck Lever return false;
138adf98a48SChuck Lever }
139adf98a48SChuck Lever
140adf98a48SChuck Lever return true;
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds /*
145cc1029b5SChuck Lever * Decode Call arguments
1461da177e4SLinus Torvalds */
147cc1029b5SChuck Lever
148c44b31c2SChuck Lever bool
nlmsvc_decode_void(struct svc_rqst * rqstp,struct xdr_stream * xdr)14916c66364SChuck Lever nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
150cc1029b5SChuck Lever {
151c44b31c2SChuck Lever return true;
152cc1029b5SChuck Lever }
153cc1029b5SChuck Lever
154c44b31c2SChuck Lever bool
nlmsvc_decode_testargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)15516c66364SChuck Lever nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1561da177e4SLinus Torvalds {
157026fec7eSChristoph Hellwig struct nlm_args *argp = rqstp->rq_argp;
1581da177e4SLinus Torvalds u32 exclusive;
1591da177e4SLinus Torvalds
1602fd0c67aSChuck Lever if (!svcxdr_decode_cookie(xdr, &argp->cookie))
161c44b31c2SChuck Lever return false;
1622fd0c67aSChuck Lever if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
163c44b31c2SChuck Lever return false;
1642fd0c67aSChuck Lever if (!svcxdr_decode_lock(xdr, &argp->lock))
165c44b31c2SChuck Lever return false;
1661da177e4SLinus Torvalds if (exclusive)
1671da177e4SLinus Torvalds argp->lock.fl.fl_type = F_WRLCK;
1681da177e4SLinus Torvalds
169c44b31c2SChuck Lever return true;
1701da177e4SLinus Torvalds }
1711da177e4SLinus Torvalds
172c44b31c2SChuck Lever bool
nlmsvc_decode_lockargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)17316c66364SChuck Lever nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
174c1adb8c6SChuck Lever {
175c1adb8c6SChuck Lever struct nlm_args *argp = rqstp->rq_argp;
176c1adb8c6SChuck Lever u32 exclusive;
177c1adb8c6SChuck Lever
178c1adb8c6SChuck Lever if (!svcxdr_decode_cookie(xdr, &argp->cookie))
179c44b31c2SChuck Lever return false;
180c1adb8c6SChuck Lever if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
181c44b31c2SChuck Lever return false;
182c1adb8c6SChuck Lever if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
183c44b31c2SChuck Lever return false;
184c1adb8c6SChuck Lever if (!svcxdr_decode_lock(xdr, &argp->lock))
185c44b31c2SChuck Lever return false;
186c1adb8c6SChuck Lever if (exclusive)
187c1adb8c6SChuck Lever argp->lock.fl.fl_type = F_WRLCK;
188c1adb8c6SChuck Lever if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
189c44b31c2SChuck Lever return false;
190c1adb8c6SChuck Lever if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
191c44b31c2SChuck Lever return false;
192c1adb8c6SChuck Lever argp->monitor = 1; /* monitor client by default */
193c1adb8c6SChuck Lever
194c44b31c2SChuck Lever return true;
195c1adb8c6SChuck Lever }
196c1adb8c6SChuck Lever
197c44b31c2SChuck Lever bool
nlmsvc_decode_cancargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)19816c66364SChuck Lever nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
199f4e08f3aSChuck Lever {
200f4e08f3aSChuck Lever struct nlm_args *argp = rqstp->rq_argp;
201f4e08f3aSChuck Lever u32 exclusive;
202f4e08f3aSChuck Lever
203f4e08f3aSChuck Lever if (!svcxdr_decode_cookie(xdr, &argp->cookie))
204c44b31c2SChuck Lever return false;
205f4e08f3aSChuck Lever if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
206c44b31c2SChuck Lever return false;
207f4e08f3aSChuck Lever if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
208c44b31c2SChuck Lever return false;
209f4e08f3aSChuck Lever if (!svcxdr_decode_lock(xdr, &argp->lock))
210c44b31c2SChuck Lever return false;
211f4e08f3aSChuck Lever if (exclusive)
212f4e08f3aSChuck Lever argp->lock.fl.fl_type = F_WRLCK;
213f4e08f3aSChuck Lever
214c44b31c2SChuck Lever return true;
215f4e08f3aSChuck Lever }
216f4e08f3aSChuck Lever
217c44b31c2SChuck Lever bool
nlmsvc_decode_unlockargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)21816c66364SChuck Lever nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
219c27045d3SChuck Lever {
220c27045d3SChuck Lever struct nlm_args *argp = rqstp->rq_argp;
221c27045d3SChuck Lever
222c27045d3SChuck Lever if (!svcxdr_decode_cookie(xdr, &argp->cookie))
223c44b31c2SChuck Lever return false;
224c27045d3SChuck Lever if (!svcxdr_decode_lock(xdr, &argp->lock))
225c44b31c2SChuck Lever return false;
226c27045d3SChuck Lever argp->lock.fl.fl_type = F_UNLCK;
227c27045d3SChuck Lever
228c44b31c2SChuck Lever return true;
229c27045d3SChuck Lever }
230c27045d3SChuck Lever
231c44b31c2SChuck Lever bool
nlmsvc_decode_res(struct svc_rqst * rqstp,struct xdr_stream * xdr)23216c66364SChuck Lever nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
23316ddcabeSChuck Lever {
23416ddcabeSChuck Lever struct nlm_res *resp = rqstp->rq_argp;
23516ddcabeSChuck Lever
23616ddcabeSChuck Lever if (!svcxdr_decode_cookie(xdr, &resp->cookie))
237c44b31c2SChuck Lever return false;
23816ddcabeSChuck Lever if (!svcxdr_decode_stats(xdr, &resp->status))
239c44b31c2SChuck Lever return false;
24016ddcabeSChuck Lever
241c44b31c2SChuck Lever return true;
24216ddcabeSChuck Lever }
24316ddcabeSChuck Lever
244c44b31c2SChuck Lever bool
nlmsvc_decode_reboot(struct svc_rqst * rqstp,struct xdr_stream * xdr)24516c66364SChuck Lever nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr)
246137e05e2SChuck Lever {
247137e05e2SChuck Lever struct nlm_reboot *argp = rqstp->rq_argp;
24816c66364SChuck Lever __be32 *p;
249137e05e2SChuck Lever u32 len;
250137e05e2SChuck Lever
251137e05e2SChuck Lever if (xdr_stream_decode_u32(xdr, &len) < 0)
252c44b31c2SChuck Lever return false;
253137e05e2SChuck Lever if (len > SM_MAXSTRLEN)
254c44b31c2SChuck Lever return false;
255137e05e2SChuck Lever p = xdr_inline_decode(xdr, len);
256137e05e2SChuck Lever if (!p)
257c44b31c2SChuck Lever return false;
258137e05e2SChuck Lever argp->len = len;
259137e05e2SChuck Lever argp->mon = (char *)p;
260137e05e2SChuck Lever if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
261c44b31c2SChuck Lever return false;
262137e05e2SChuck Lever p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
263137e05e2SChuck Lever if (!p)
264c44b31c2SChuck Lever return false;
265137e05e2SChuck Lever memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
266137e05e2SChuck Lever
267c44b31c2SChuck Lever return true;
268137e05e2SChuck Lever }
269137e05e2SChuck Lever
270c44b31c2SChuck Lever bool
nlmsvc_decode_shareargs(struct svc_rqst * rqstp,struct xdr_stream * xdr)27116c66364SChuck Lever nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
2721da177e4SLinus Torvalds {
273026fec7eSChristoph Hellwig struct nlm_args *argp = rqstp->rq_argp;
2741da177e4SLinus Torvalds struct nlm_lock *lock = &argp->lock;
2751da177e4SLinus Torvalds
2761da177e4SLinus Torvalds memset(lock, 0, sizeof(*lock));
2771da177e4SLinus Torvalds locks_init_lock(&lock->fl);
2787bab377fSTrond Myklebust lock->svid = ~(u32)0;
2791da177e4SLinus Torvalds
280890939e1SChuck Lever if (!svcxdr_decode_cookie(xdr, &argp->cookie))
281c44b31c2SChuck Lever return false;
282890939e1SChuck Lever if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
283c44b31c2SChuck Lever return false;
284890939e1SChuck Lever if (!svcxdr_decode_fhandle(xdr, &lock->fh))
285c44b31c2SChuck Lever return false;
286890939e1SChuck Lever if (!svcxdr_decode_owner(xdr, &lock->oh))
287c44b31c2SChuck Lever return false;
288890939e1SChuck Lever /* XXX: Range checks are missing in the original code */
289890939e1SChuck Lever if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
290c44b31c2SChuck Lever return false;
291890939e1SChuck Lever if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
292c44b31c2SChuck Lever return false;
293890939e1SChuck Lever
294c44b31c2SChuck Lever return true;
295890939e1SChuck Lever }
296890939e1SChuck Lever
297c44b31c2SChuck Lever bool
nlmsvc_decode_notify(struct svc_rqst * rqstp,struct xdr_stream * xdr)29816c66364SChuck Lever nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr)
29914e10525SChuck Lever {
30014e10525SChuck Lever struct nlm_args *argp = rqstp->rq_argp;
30114e10525SChuck Lever struct nlm_lock *lock = &argp->lock;
30214e10525SChuck Lever
30314e10525SChuck Lever if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
304c44b31c2SChuck Lever return false;
30514e10525SChuck Lever if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
306c44b31c2SChuck Lever return false;
30714e10525SChuck Lever
308c44b31c2SChuck Lever return true;
30914e10525SChuck Lever }
31014e10525SChuck Lever
311e26ec898SChuck Lever
312e26ec898SChuck Lever /*
313e26ec898SChuck Lever * Encode Reply results
314e26ec898SChuck Lever */
315e26ec898SChuck Lever
316*130e2054SChuck Lever bool
nlmsvc_encode_void(struct svc_rqst * rqstp,struct xdr_stream * xdr)317fda49441SChuck Lever nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
318e26ec898SChuck Lever {
319*130e2054SChuck Lever return true;
320e26ec898SChuck Lever }
321e26ec898SChuck Lever
322*130e2054SChuck Lever bool
nlmsvc_encode_testres(struct svc_rqst * rqstp,struct xdr_stream * xdr)323fda49441SChuck Lever nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
324890939e1SChuck Lever {
325890939e1SChuck Lever struct nlm_res *resp = rqstp->rq_resp;
326890939e1SChuck Lever
327adf98a48SChuck Lever return svcxdr_encode_cookie(xdr, &resp->cookie) &&
328adf98a48SChuck Lever svcxdr_encode_testrply(xdr, resp);
3291da177e4SLinus Torvalds }
3301da177e4SLinus Torvalds
331*130e2054SChuck Lever bool
nlmsvc_encode_res(struct svc_rqst * rqstp,struct xdr_stream * xdr)332fda49441SChuck Lever nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
333e96735a6SChuck Lever {
334e96735a6SChuck Lever struct nlm_res *resp = rqstp->rq_resp;
335e96735a6SChuck Lever
336e96735a6SChuck Lever return svcxdr_encode_cookie(xdr, &resp->cookie) &&
337e96735a6SChuck Lever svcxdr_encode_stats(xdr, resp->status);
338e96735a6SChuck Lever }
339e96735a6SChuck Lever
340*130e2054SChuck Lever bool
nlmsvc_encode_shareres(struct svc_rqst * rqstp,struct xdr_stream * xdr)341fda49441SChuck Lever nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
3421da177e4SLinus Torvalds {
34363f8de37SChristoph Hellwig struct nlm_res *resp = rqstp->rq_resp;
34463f8de37SChristoph Hellwig
345529ca3a1SChuck Lever if (!svcxdr_encode_cookie(xdr, &resp->cookie))
346*130e2054SChuck Lever return false;
347529ca3a1SChuck Lever if (!svcxdr_encode_stats(xdr, resp->status))
348*130e2054SChuck Lever return false;
349529ca3a1SChuck Lever /* sequence */
350529ca3a1SChuck Lever if (xdr_stream_encode_u32(xdr, 0) < 0)
351*130e2054SChuck Lever return false;
352529ca3a1SChuck Lever
353*130e2054SChuck Lever return true;
3541da177e4SLinus Torvalds }
355