2dbf82c2726be0c3c9eff91612e62dddee2e4c50
[linux-block.git] / fs / lockd / xdr4.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * linux/fs/lockd/xdr4.c
4  *
5  * XDR support for lockd and the lock client.
6  *
7  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
8  * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
9  */
10
11 #include <linux/types.h>
12 #include <linux/sched.h>
13 #include <linux/nfs.h>
14
15 #include <linux/sunrpc/xdr.h>
16 #include <linux/sunrpc/clnt.h>
17 #include <linux/sunrpc/svc.h>
18 #include <linux/sunrpc/stats.h>
19 #include <linux/lockd/lockd.h>
20
21 #include "svcxdr.h"
22
23 #define NLMDBG_FACILITY         NLMDBG_XDR
24
25 static inline loff_t
26 s64_to_loff_t(__s64 offset)
27 {
28         return (loff_t)offset;
29 }
30
31
32 static inline s64
33 loff_t_to_s64(loff_t offset)
34 {
35         s64 res;
36         if (offset > NLM4_OFFSET_MAX)
37                 res = NLM4_OFFSET_MAX;
38         else if (offset < -NLM4_OFFSET_MAX)
39                 res = -NLM4_OFFSET_MAX;
40         else
41                 res = offset;
42         return res;
43 }
44
45 /*
46  * XDR functions for basic NLM types
47  */
48 static __be32 *
49 nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
50 {
51         unsigned int    len;
52
53         len = ntohl(*p++);
54         
55         if(len==0)
56         {
57                 c->len=4;
58                 memset(c->data, 0, 4);  /* hockeypux brain damage */
59         }
60         else if(len<=NLM_MAXCOOKIELEN)
61         {
62                 c->len=len;
63                 memcpy(c->data, p, len);
64                 p+=XDR_QUADLEN(len);
65         }
66         else 
67         {
68                 dprintk("lockd: bad cookie size %d (only cookies under "
69                         "%d bytes are supported.)\n",
70                                 len, NLM_MAXCOOKIELEN);
71                 return NULL;
72         }
73         return p;
74 }
75
76 static __be32 *
77 nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
78 {
79         *p++ = htonl(c->len);
80         memcpy(p, c->data, c->len);
81         p+=XDR_QUADLEN(c->len);
82         return p;
83 }
84
85 static __be32 *
86 nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
87 {
88         memset(f->data, 0, sizeof(f->data));
89         f->size = ntohl(*p++);
90         if (f->size > NFS_MAXFHSIZE) {
91                 dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
92                         f->size, NFS_MAXFHSIZE);
93                 return NULL;
94         }
95         memcpy(f->data, p, f->size);
96         return p + XDR_QUADLEN(f->size);
97 }
98
99 /*
100  * NLM file handles are defined by specification to be a variable-length
101  * XDR opaque no longer than 1024 bytes. However, this implementation
102  * limits their length to the size of an NFSv3 file handle.
103  */
104 static bool
105 svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
106 {
107         __be32 *p;
108         u32 len;
109
110         if (xdr_stream_decode_u32(xdr, &len) < 0)
111                 return false;
112         if (len > NFS_MAXFHSIZE)
113                 return false;
114
115         p = xdr_inline_decode(xdr, len);
116         if (!p)
117                 return false;
118         fh->size = len;
119         memcpy(fh->data, p, len);
120         memset(fh->data + len, 0, sizeof(fh->data) - len);
121
122         return true;
123 }
124
125 /*
126  * Encode and decode owner handle
127  */
128 static __be32 *
129 nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
130 {
131         return xdr_decode_netobj(p, oh);
132 }
133
134 static bool
135 svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
136 {
137         struct file_lock *fl = &lock->fl;
138         u64 len, start;
139         s64 end;
140
141         if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
142                 return false;
143         if (!svcxdr_decode_fhandle(xdr, &lock->fh))
144                 return false;
145         if (!svcxdr_decode_owner(xdr, &lock->oh))
146                 return false;
147         if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
148                 return false;
149         if (xdr_stream_decode_u64(xdr, &start) < 0)
150                 return false;
151         if (xdr_stream_decode_u64(xdr, &len) < 0)
152                 return false;
153
154         locks_init_lock(fl);
155         fl->fl_flags = FL_POSIX;
156         fl->fl_type  = F_RDLCK;
157         end = start + len - 1;
158         fl->fl_start = s64_to_loff_t(start);
159         if (len == 0 || end < 0)
160                 fl->fl_end = OFFSET_MAX;
161         else
162                 fl->fl_end = s64_to_loff_t(end);
163
164         return true;
165 }
166
167 /*
168  * Encode result of a TEST/TEST_MSG call
169  */
170 static __be32 *
171 nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
172 {
173         s64             start, len;
174
175         dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
176         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
177                 return NULL;
178         *p++ = resp->status;
179
180         if (resp->status == nlm_lck_denied) {
181                 struct file_lock        *fl = &resp->lock.fl;
182
183                 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
184                 *p++ = htonl(resp->lock.svid);
185
186                 /* Encode owner handle. */
187                 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
188                         return NULL;
189
190                 start = loff_t_to_s64(fl->fl_start);
191                 if (fl->fl_end == OFFSET_MAX)
192                         len = 0;
193                 else
194                         len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
195                 
196                 p = xdr_encode_hyper(p, start);
197                 p = xdr_encode_hyper(p, len);
198                 dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n",
199                         resp->status, (int)resp->lock.svid, fl->fl_type,
200                         (long long)fl->fl_start,  (long long)fl->fl_end);
201         }
202
203         dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
204         return p;
205 }
206
207
208 /*
209  * Decode Call arguments
210  */
211
212 int
213 nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p)
214 {
215         return 1;
216 }
217
218 int
219 nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
220 {
221         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
222         struct nlm_args *argp = rqstp->rq_argp;
223         u32 exclusive;
224
225         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
226                 return 0;
227         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
228                 return 0;
229         if (!svcxdr_decode_lock(xdr, &argp->lock))
230                 return 0;
231         if (exclusive)
232                 argp->lock.fl.fl_type = F_WRLCK;
233
234         return 1;
235 }
236
237 int
238 nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
239 {
240         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
241         struct nlm_args *argp = rqstp->rq_argp;
242         u32 exclusive;
243
244         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
245                 return 0;
246         if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
247                 return 0;
248         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
249                 return 0;
250         if (!svcxdr_decode_lock(xdr, &argp->lock))
251                 return 0;
252         if (exclusive)
253                 argp->lock.fl.fl_type = F_WRLCK;
254         if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
255                 return 0;
256         if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
257                 return 0;
258         argp->monitor = 1;              /* monitor client by default */
259
260         return 1;
261 }
262
263 int
264 nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
265 {
266         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
267         struct nlm_args *argp = rqstp->rq_argp;
268         u32 exclusive;
269
270         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
271                 return 0;
272         if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
273                 return 0;
274         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
275                 return 0;
276         if (!svcxdr_decode_lock(xdr, &argp->lock))
277                 return 0;
278         if (exclusive)
279                 argp->lock.fl.fl_type = F_WRLCK;
280         return 1;
281 }
282
283 int
284 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
285 {
286         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
287         struct nlm_args *argp = rqstp->rq_argp;
288
289         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
290                 return 0;
291         if (!svcxdr_decode_lock(xdr, &argp->lock))
292                 return 0;
293         argp->lock.fl.fl_type = F_UNLCK;
294
295         return 1;
296 }
297
298 int
299 nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p)
300 {
301         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
302         struct nlm_res *resp = rqstp->rq_argp;
303
304         if (!svcxdr_decode_cookie(xdr, &resp->cookie))
305                 return 0;
306         if (!svcxdr_decode_stats(xdr, &resp->status))
307                 return 0;
308
309         return 1;
310 }
311
312 int
313 nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
314 {
315         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
316         struct nlm_reboot *argp = rqstp->rq_argp;
317         u32 len;
318
319         if (xdr_stream_decode_u32(xdr, &len) < 0)
320                 return 0;
321         if (len > SM_MAXSTRLEN)
322                 return 0;
323         p = xdr_inline_decode(xdr, len);
324         if (!p)
325                 return 0;
326         argp->len = len;
327         argp->mon = (char *)p;
328         if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
329                 return 0;
330         p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
331         if (!p)
332                 return 0;
333         memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
334
335         return 1;
336 }
337
338 int
339 nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
340 {
341         struct nlm_res *resp = rqstp->rq_resp;
342
343         if (!(p = nlm4_encode_testres(p, resp)))
344                 return 0;
345         return xdr_ressize_check(rqstp, p);
346 }
347
348 int
349 nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
350 {
351         struct nlm_args *argp = rqstp->rq_argp;
352         struct nlm_lock *lock = &argp->lock;
353
354         memset(lock, 0, sizeof(*lock));
355         locks_init_lock(&lock->fl);
356         lock->svid = ~(u32) 0;
357
358         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
359          || !(p = xdr_decode_string_inplace(p, &lock->caller,
360                                             &lock->len, NLM_MAXSTRLEN))
361          || !(p = nlm4_decode_fh(p, &lock->fh))
362          || !(p = nlm4_decode_oh(p, &lock->oh)))
363                 return 0;
364         argp->fsm_mode = ntohl(*p++);
365         argp->fsm_access = ntohl(*p++);
366         return xdr_argsize_check(rqstp, p);
367 }
368
369 int
370 nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
371 {
372         struct nlm_res *resp = rqstp->rq_resp;
373
374         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
375                 return 0;
376         *p++ = resp->status;
377         *p++ = xdr_zero;                /* sequence argument */
378         return xdr_ressize_check(rqstp, p);
379 }
380
381 int
382 nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p)
383 {
384         struct nlm_res *resp = rqstp->rq_resp;
385
386         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
387                 return 0;
388         *p++ = resp->status;
389         return xdr_ressize_check(rqstp, p);
390 }
391
392 int
393 nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
394 {
395         struct nlm_args *argp = rqstp->rq_argp;
396         struct nlm_lock *lock = &argp->lock;
397
398         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
399                                             &lock->len, NLM_MAXSTRLEN)))
400                 return 0;
401         argp->state = ntohl(*p++);
402         return xdr_argsize_check(rqstp, p);
403 }
404
405 int
406 nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p)
407 {
408         return xdr_ressize_check(rqstp, p);
409 }