lockd: Update the NLMv4 CANCEL arguments decoder to use struct xdr_stream
[linux-2.6-microblaze.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 __be32 *
135 nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
136 {
137         struct file_lock        *fl = &lock->fl;
138         __u64                   len, start;
139         __s64                   end;
140
141         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
142                                             &lock->len, NLM_MAXSTRLEN))
143          || !(p = nlm4_decode_fh(p, &lock->fh))
144          || !(p = nlm4_decode_oh(p, &lock->oh)))
145                 return NULL;
146         lock->svid  = ntohl(*p++);
147
148         locks_init_lock(fl);
149         fl->fl_flags = FL_POSIX;
150         fl->fl_type  = F_RDLCK;         /* as good as anything else */
151         p = xdr_decode_hyper(p, &start);
152         p = xdr_decode_hyper(p, &len);
153         end = start + len - 1;
154
155         fl->fl_start = s64_to_loff_t(start);
156
157         if (len == 0 || end < 0)
158                 fl->fl_end = OFFSET_MAX;
159         else
160                 fl->fl_end = s64_to_loff_t(end);
161         return p;
162 }
163
164 static bool
165 svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
166 {
167         struct file_lock *fl = &lock->fl;
168         u64 len, start;
169         s64 end;
170
171         if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
172                 return false;
173         if (!svcxdr_decode_fhandle(xdr, &lock->fh))
174                 return false;
175         if (!svcxdr_decode_owner(xdr, &lock->oh))
176                 return false;
177         if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
178                 return false;
179         if (xdr_stream_decode_u64(xdr, &start) < 0)
180                 return false;
181         if (xdr_stream_decode_u64(xdr, &len) < 0)
182                 return false;
183
184         locks_init_lock(fl);
185         fl->fl_flags = FL_POSIX;
186         fl->fl_type  = F_RDLCK;
187         end = start + len - 1;
188         fl->fl_start = s64_to_loff_t(start);
189         if (len == 0 || end < 0)
190                 fl->fl_end = OFFSET_MAX;
191         else
192                 fl->fl_end = s64_to_loff_t(end);
193
194         return true;
195 }
196
197 /*
198  * Encode result of a TEST/TEST_MSG call
199  */
200 static __be32 *
201 nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
202 {
203         s64             start, len;
204
205         dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
206         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
207                 return NULL;
208         *p++ = resp->status;
209
210         if (resp->status == nlm_lck_denied) {
211                 struct file_lock        *fl = &resp->lock.fl;
212
213                 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
214                 *p++ = htonl(resp->lock.svid);
215
216                 /* Encode owner handle. */
217                 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
218                         return NULL;
219
220                 start = loff_t_to_s64(fl->fl_start);
221                 if (fl->fl_end == OFFSET_MAX)
222                         len = 0;
223                 else
224                         len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
225                 
226                 p = xdr_encode_hyper(p, start);
227                 p = xdr_encode_hyper(p, len);
228                 dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n",
229                         resp->status, (int)resp->lock.svid, fl->fl_type,
230                         (long long)fl->fl_start,  (long long)fl->fl_end);
231         }
232
233         dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
234         return p;
235 }
236
237
238 /*
239  * Decode Call arguments
240  */
241
242 int
243 nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p)
244 {
245         return 1;
246 }
247
248 int
249 nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
250 {
251         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
252         struct nlm_args *argp = rqstp->rq_argp;
253         u32 exclusive;
254
255         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
256                 return 0;
257         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
258                 return 0;
259         if (!svcxdr_decode_lock(xdr, &argp->lock))
260                 return 0;
261         if (exclusive)
262                 argp->lock.fl.fl_type = F_WRLCK;
263
264         return 1;
265 }
266
267 int
268 nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
269 {
270         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
271         struct nlm_args *argp = rqstp->rq_argp;
272         u32 exclusive;
273
274         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
275                 return 0;
276         if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
277                 return 0;
278         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
279                 return 0;
280         if (!svcxdr_decode_lock(xdr, &argp->lock))
281                 return 0;
282         if (exclusive)
283                 argp->lock.fl.fl_type = F_WRLCK;
284         if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
285                 return 0;
286         if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
287                 return 0;
288         argp->monitor = 1;              /* monitor client by default */
289
290         return 1;
291 }
292
293 int
294 nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
295 {
296         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
297         struct nlm_args *argp = rqstp->rq_argp;
298         u32 exclusive;
299
300         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
301                 return 0;
302         if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
303                 return 0;
304         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
305                 return 0;
306         if (!svcxdr_decode_lock(xdr, &argp->lock))
307                 return 0;
308         if (exclusive)
309                 argp->lock.fl.fl_type = F_WRLCK;
310         return 1;
311 }
312
313 int
314 nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
315 {
316         struct nlm_res *resp = rqstp->rq_resp;
317
318         if (!(p = nlm4_encode_testres(p, resp)))
319                 return 0;
320         return xdr_ressize_check(rqstp, p);
321 }
322
323 int
324 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
325 {
326         struct nlm_args *argp = rqstp->rq_argp;
327
328         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
329          || !(p = nlm4_decode_lock(p, &argp->lock)))
330                 return 0;
331         argp->lock.fl.fl_type = F_UNLCK;
332         return xdr_argsize_check(rqstp, p);
333 }
334
335 int
336 nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
337 {
338         struct nlm_args *argp = rqstp->rq_argp;
339         struct nlm_lock *lock = &argp->lock;
340
341         memset(lock, 0, sizeof(*lock));
342         locks_init_lock(&lock->fl);
343         lock->svid = ~(u32) 0;
344
345         if (!(p = nlm4_decode_cookie(p, &argp->cookie))
346          || !(p = xdr_decode_string_inplace(p, &lock->caller,
347                                             &lock->len, NLM_MAXSTRLEN))
348          || !(p = nlm4_decode_fh(p, &lock->fh))
349          || !(p = nlm4_decode_oh(p, &lock->oh)))
350                 return 0;
351         argp->fsm_mode = ntohl(*p++);
352         argp->fsm_access = ntohl(*p++);
353         return xdr_argsize_check(rqstp, p);
354 }
355
356 int
357 nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
358 {
359         struct nlm_res *resp = rqstp->rq_resp;
360
361         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
362                 return 0;
363         *p++ = resp->status;
364         *p++ = xdr_zero;                /* sequence argument */
365         return xdr_ressize_check(rqstp, p);
366 }
367
368 int
369 nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p)
370 {
371         struct nlm_res *resp = rqstp->rq_resp;
372
373         if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
374                 return 0;
375         *p++ = resp->status;
376         return xdr_ressize_check(rqstp, p);
377 }
378
379 int
380 nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
381 {
382         struct nlm_args *argp = rqstp->rq_argp;
383         struct nlm_lock *lock = &argp->lock;
384
385         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
386                                             &lock->len, NLM_MAXSTRLEN)))
387                 return 0;
388         argp->state = ntohl(*p++);
389         return xdr_argsize_check(rqstp, p);
390 }
391
392 int
393 nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
394 {
395         struct nlm_reboot *argp = rqstp->rq_argp;
396
397         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
398                 return 0;
399         argp->state = ntohl(*p++);
400         memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
401         p += XDR_QUADLEN(SM_PRIV_SIZE);
402         return xdr_argsize_check(rqstp, p);
403 }
404
405 int
406 nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p)
407 {
408         struct nlm_res *resp = rqstp->rq_argp;
409
410         if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
411                 return 0;
412         resp->status = *p++;
413         return xdr_argsize_check(rqstp, p);
414 }
415
416 int
417 nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p)
418 {
419         return xdr_ressize_check(rqstp, p);
420 }