xref: /kernel/linux/linux-5.10/fs/lockd/xdr.c (revision 8c2ecf20)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * linux/fs/lockd/xdr.c
4 *
5 * XDR support for lockd and the lock client.
6 *
7 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
8 */
9
10#include <linux/types.h>
11#include <linux/sched.h>
12#include <linux/nfs.h>
13
14#include <linux/sunrpc/xdr.h>
15#include <linux/sunrpc/clnt.h>
16#include <linux/sunrpc/svc.h>
17#include <linux/sunrpc/stats.h>
18#include <linux/lockd/lockd.h>
19
20#include <uapi/linux/nfs2.h>
21
22#define NLMDBG_FACILITY		NLMDBG_XDR
23
24
25static inline loff_t
26s32_to_loff_t(__s32 offset)
27{
28	return (loff_t)offset;
29}
30
31static inline __s32
32loff_t_to_s32(loff_t offset)
33{
34	__s32 res;
35	if (offset >= NLM_OFFSET_MAX)
36		res = NLM_OFFSET_MAX;
37	else if (offset <= -NLM_OFFSET_MAX)
38		res = -NLM_OFFSET_MAX;
39	else
40		res = offset;
41	return res;
42}
43
44/*
45 * XDR functions for basic NLM types
46 */
47static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
48{
49	unsigned int	len;
50
51	len = ntohl(*p++);
52
53	if(len==0)
54	{
55		c->len=4;
56		memset(c->data, 0, 4);	/* hockeypux brain damage */
57	}
58	else if(len<=NLM_MAXCOOKIELEN)
59	{
60		c->len=len;
61		memcpy(c->data, p, len);
62		p+=XDR_QUADLEN(len);
63	}
64	else
65	{
66		dprintk("lockd: bad cookie size %d (only cookies under "
67			"%d bytes are supported.)\n",
68				len, NLM_MAXCOOKIELEN);
69		return NULL;
70	}
71	return p;
72}
73
74static inline __be32 *
75nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
76{
77	*p++ = htonl(c->len);
78	memcpy(p, c->data, c->len);
79	p+=XDR_QUADLEN(c->len);
80	return p;
81}
82
83static __be32 *
84nlm_decode_fh(__be32 *p, struct nfs_fh *f)
85{
86	unsigned int	len;
87
88	if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
89		dprintk("lockd: bad fhandle size %d (should be %d)\n",
90			len, NFS2_FHSIZE);
91		return NULL;
92	}
93	f->size = NFS2_FHSIZE;
94	memset(f->data, 0, sizeof(f->data));
95	memcpy(f->data, p, NFS2_FHSIZE);
96	return p + XDR_QUADLEN(NFS2_FHSIZE);
97}
98
99/*
100 * Encode and decode owner handle
101 */
102static inline __be32 *
103nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
104{
105	return xdr_decode_netobj(p, oh);
106}
107
108static inline __be32 *
109nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
110{
111	return xdr_encode_netobj(p, oh);
112}
113
114static __be32 *
115nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
116{
117	struct file_lock	*fl = &lock->fl;
118	s32			start, len, end;
119
120	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
121					    &lock->len,
122					    NLM_MAXSTRLEN))
123	 || !(p = nlm_decode_fh(p, &lock->fh))
124	 || !(p = nlm_decode_oh(p, &lock->oh)))
125		return NULL;
126	lock->svid  = ntohl(*p++);
127
128	locks_init_lock(fl);
129	fl->fl_flags = FL_POSIX;
130	fl->fl_type  = F_RDLCK;		/* as good as anything else */
131	start = ntohl(*p++);
132	len = ntohl(*p++);
133	end = start + len - 1;
134
135	fl->fl_start = s32_to_loff_t(start);
136
137	if (len == 0 || end < 0)
138		fl->fl_end = OFFSET_MAX;
139	else
140		fl->fl_end = s32_to_loff_t(end);
141	return p;
142}
143
144/*
145 * Encode result of a TEST/TEST_MSG call
146 */
147static __be32 *
148nlm_encode_testres(__be32 *p, struct nlm_res *resp)
149{
150	s32		start, len;
151
152	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
153		return NULL;
154	*p++ = resp->status;
155
156	if (resp->status == nlm_lck_denied) {
157		struct file_lock	*fl = &resp->lock.fl;
158
159		*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
160		*p++ = htonl(resp->lock.svid);
161
162		/* Encode owner handle. */
163		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
164			return NULL;
165
166		start = loff_t_to_s32(fl->fl_start);
167		if (fl->fl_end == OFFSET_MAX)
168			len = 0;
169		else
170			len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
171
172		*p++ = htonl(start);
173		*p++ = htonl(len);
174	}
175
176	return p;
177}
178
179
180/*
181 * First, the server side XDR functions
182 */
183int
184nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
185{
186	struct nlm_args *argp = rqstp->rq_argp;
187	u32	exclusive;
188
189	if (!(p = nlm_decode_cookie(p, &argp->cookie)))
190		return 0;
191
192	exclusive = ntohl(*p++);
193	if (!(p = nlm_decode_lock(p, &argp->lock)))
194		return 0;
195	if (exclusive)
196		argp->lock.fl.fl_type = F_WRLCK;
197
198	return xdr_argsize_check(rqstp, p);
199}
200
201int
202nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
203{
204	struct nlm_res *resp = rqstp->rq_resp;
205
206	if (!(p = nlm_encode_testres(p, resp)))
207		return 0;
208	return xdr_ressize_check(rqstp, p);
209}
210
211int
212nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
213{
214	struct nlm_args *argp = rqstp->rq_argp;
215	u32	exclusive;
216
217	if (!(p = nlm_decode_cookie(p, &argp->cookie)))
218		return 0;
219	argp->block  = ntohl(*p++);
220	exclusive    = ntohl(*p++);
221	if (!(p = nlm_decode_lock(p, &argp->lock)))
222		return 0;
223	if (exclusive)
224		argp->lock.fl.fl_type = F_WRLCK;
225	argp->reclaim = ntohl(*p++);
226	argp->state   = ntohl(*p++);
227	argp->monitor = 1;		/* monitor client by default */
228
229	return xdr_argsize_check(rqstp, p);
230}
231
232int
233nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
234{
235	struct nlm_args *argp = rqstp->rq_argp;
236	u32	exclusive;
237
238	if (!(p = nlm_decode_cookie(p, &argp->cookie)))
239		return 0;
240	argp->block = ntohl(*p++);
241	exclusive = ntohl(*p++);
242	if (!(p = nlm_decode_lock(p, &argp->lock)))
243		return 0;
244	if (exclusive)
245		argp->lock.fl.fl_type = F_WRLCK;
246	return xdr_argsize_check(rqstp, p);
247}
248
249int
250nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
251{
252	struct nlm_args *argp = rqstp->rq_argp;
253
254	if (!(p = nlm_decode_cookie(p, &argp->cookie))
255	 || !(p = nlm_decode_lock(p, &argp->lock)))
256		return 0;
257	argp->lock.fl.fl_type = F_UNLCK;
258	return xdr_argsize_check(rqstp, p);
259}
260
261int
262nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
263{
264	struct nlm_args *argp = rqstp->rq_argp;
265	struct nlm_lock	*lock = &argp->lock;
266
267	memset(lock, 0, sizeof(*lock));
268	locks_init_lock(&lock->fl);
269	lock->svid = ~(u32) 0;
270
271	if (!(p = nlm_decode_cookie(p, &argp->cookie))
272	 || !(p = xdr_decode_string_inplace(p, &lock->caller,
273					    &lock->len, NLM_MAXSTRLEN))
274	 || !(p = nlm_decode_fh(p, &lock->fh))
275	 || !(p = nlm_decode_oh(p, &lock->oh)))
276		return 0;
277	argp->fsm_mode = ntohl(*p++);
278	argp->fsm_access = ntohl(*p++);
279	return xdr_argsize_check(rqstp, p);
280}
281
282int
283nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
284{
285	struct nlm_res *resp = rqstp->rq_resp;
286
287	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
288		return 0;
289	*p++ = resp->status;
290	*p++ = xdr_zero;		/* sequence argument */
291	return xdr_ressize_check(rqstp, p);
292}
293
294int
295nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
296{
297	struct nlm_res *resp = rqstp->rq_resp;
298
299	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
300		return 0;
301	*p++ = resp->status;
302	return xdr_ressize_check(rqstp, p);
303}
304
305int
306nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
307{
308	struct nlm_args *argp = rqstp->rq_argp;
309	struct nlm_lock	*lock = &argp->lock;
310
311	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
312					    &lock->len, NLM_MAXSTRLEN)))
313		return 0;
314	argp->state = ntohl(*p++);
315	return xdr_argsize_check(rqstp, p);
316}
317
318int
319nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
320{
321	struct nlm_reboot *argp = rqstp->rq_argp;
322
323	if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
324		return 0;
325	argp->state = ntohl(*p++);
326	memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
327	p += XDR_QUADLEN(SM_PRIV_SIZE);
328	return xdr_argsize_check(rqstp, p);
329}
330
331int
332nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
333{
334	struct nlm_res *resp = rqstp->rq_argp;
335
336	if (!(p = nlm_decode_cookie(p, &resp->cookie)))
337		return 0;
338	resp->status = *p++;
339	return xdr_argsize_check(rqstp, p);
340}
341
342int
343nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
344{
345	return xdr_argsize_check(rqstp, p);
346}
347
348int
349nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
350{
351	return xdr_ressize_check(rqstp, p);
352}
353