lockd: Update the NLMv1 UNLOCK arguments decoder to use struct xdr_stream
[linux-2.6-microblaze.git] / fs / lockd / xdr.c
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 #include "svcxdr.h"
23
24 #define NLMDBG_FACILITY         NLMDBG_XDR
25
26
27 static inline loff_t
28 s32_to_loff_t(__s32 offset)
29 {
30         return (loff_t)offset;
31 }
32
33 static inline __s32
34 loff_t_to_s32(loff_t offset)
35 {
36         __s32 res;
37         if (offset >= NLM_OFFSET_MAX)
38                 res = NLM_OFFSET_MAX;
39         else if (offset <= -NLM_OFFSET_MAX)
40                 res = -NLM_OFFSET_MAX;
41         else
42                 res = offset;
43         return res;
44 }
45
46 /*
47  * XDR functions for basic NLM types
48  */
49 static __be32 *nlm_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 inline __be32 *
77 nlm_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 nlm_decode_fh(__be32 *p, struct nfs_fh *f)
87 {
88         unsigned int    len;
89
90         if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
91                 dprintk("lockd: bad fhandle size %d (should be %d)\n",
92                         len, NFS2_FHSIZE);
93                 return NULL;
94         }
95         f->size = NFS2_FHSIZE;
96         memset(f->data, 0, sizeof(f->data));
97         memcpy(f->data, p, NFS2_FHSIZE);
98         return p + XDR_QUADLEN(NFS2_FHSIZE);
99 }
100
101 /*
102  * NLM file handles are defined by specification to be a variable-length
103  * XDR opaque no longer than 1024 bytes. However, this implementation
104  * constrains their length to exactly the length of an NFSv2 file
105  * handle.
106  */
107 static bool
108 svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
109 {
110         __be32 *p;
111         u32 len;
112
113         if (xdr_stream_decode_u32(xdr, &len) < 0)
114                 return false;
115         if (len != NFS2_FHSIZE)
116                 return false;
117
118         p = xdr_inline_decode(xdr, len);
119         if (!p)
120                 return false;
121         fh->size = NFS2_FHSIZE;
122         memcpy(fh->data, p, len);
123         memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
124
125         return true;
126 }
127
128 /*
129  * Encode and decode owner handle
130  */
131 static inline __be32 *
132 nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
133 {
134         return xdr_decode_netobj(p, oh);
135 }
136
137 static inline __be32 *
138 nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
139 {
140         return xdr_encode_netobj(p, oh);
141 }
142
143 static bool
144 svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
145 {
146         struct file_lock *fl = &lock->fl;
147         s32 start, len, end;
148
149         if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
150                 return false;
151         if (!svcxdr_decode_fhandle(xdr, &lock->fh))
152                 return false;
153         if (!svcxdr_decode_owner(xdr, &lock->oh))
154                 return false;
155         if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
156                 return false;
157         if (xdr_stream_decode_u32(xdr, &start) < 0)
158                 return false;
159         if (xdr_stream_decode_u32(xdr, &len) < 0)
160                 return false;
161
162         locks_init_lock(fl);
163         fl->fl_flags = FL_POSIX;
164         fl->fl_type  = F_RDLCK;
165         end = start + len - 1;
166         fl->fl_start = s32_to_loff_t(start);
167         if (len == 0 || end < 0)
168                 fl->fl_end = OFFSET_MAX;
169         else
170                 fl->fl_end = s32_to_loff_t(end);
171
172         return true;
173 }
174
175 /*
176  * Encode result of a TEST/TEST_MSG call
177  */
178 static __be32 *
179 nlm_encode_testres(__be32 *p, struct nlm_res *resp)
180 {
181         s32             start, len;
182
183         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
184                 return NULL;
185         *p++ = resp->status;
186
187         if (resp->status == nlm_lck_denied) {
188                 struct file_lock        *fl = &resp->lock.fl;
189
190                 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
191                 *p++ = htonl(resp->lock.svid);
192
193                 /* Encode owner handle. */
194                 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
195                         return NULL;
196
197                 start = loff_t_to_s32(fl->fl_start);
198                 if (fl->fl_end == OFFSET_MAX)
199                         len = 0;
200                 else
201                         len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
202
203                 *p++ = htonl(start);
204                 *p++ = htonl(len);
205         }
206
207         return p;
208 }
209
210
211 /*
212  * Decode Call arguments
213  */
214
215 int
216 nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
217 {
218         return 1;
219 }
220
221 int
222 nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
223 {
224         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
225         struct nlm_args *argp = rqstp->rq_argp;
226         u32 exclusive;
227
228         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
229                 return 0;
230         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
231                 return 0;
232         if (!svcxdr_decode_lock(xdr, &argp->lock))
233                 return 0;
234         if (exclusive)
235                 argp->lock.fl.fl_type = F_WRLCK;
236
237         return 1;
238 }
239
240 int
241 nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
242 {
243         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
244         struct nlm_args *argp = rqstp->rq_argp;
245         u32 exclusive;
246
247         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
248                 return 0;
249         if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
250                 return 0;
251         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
252                 return 0;
253         if (!svcxdr_decode_lock(xdr, &argp->lock))
254                 return 0;
255         if (exclusive)
256                 argp->lock.fl.fl_type = F_WRLCK;
257         if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
258                 return 0;
259         if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
260                 return 0;
261         argp->monitor = 1;              /* monitor client by default */
262
263         return 1;
264 }
265
266 int
267 nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
268 {
269         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
270         struct nlm_args *argp = rqstp->rq_argp;
271         u32 exclusive;
272
273         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
274                 return 0;
275         if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
276                 return 0;
277         if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
278                 return 0;
279         if (!svcxdr_decode_lock(xdr, &argp->lock))
280                 return 0;
281         if (exclusive)
282                 argp->lock.fl.fl_type = F_WRLCK;
283
284         return 1;
285 }
286
287 int
288 nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
289 {
290         struct xdr_stream *xdr = &rqstp->rq_arg_stream;
291         struct nlm_args *argp = rqstp->rq_argp;
292
293         if (!svcxdr_decode_cookie(xdr, &argp->cookie))
294                 return 0;
295         if (!svcxdr_decode_lock(xdr, &argp->lock))
296                 return 0;
297         argp->lock.fl.fl_type = F_UNLCK;
298
299         return 1;
300 }
301
302 int
303 nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
304 {
305         struct nlm_res *resp = rqstp->rq_resp;
306
307         if (!(p = nlm_encode_testres(p, resp)))
308                 return 0;
309         return xdr_ressize_check(rqstp, p);
310 }
311
312 int
313 nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
314 {
315         struct nlm_args *argp = rqstp->rq_argp;
316         struct nlm_lock *lock = &argp->lock;
317
318         memset(lock, 0, sizeof(*lock));
319         locks_init_lock(&lock->fl);
320         lock->svid = ~(u32) 0;
321
322         if (!(p = nlm_decode_cookie(p, &argp->cookie))
323          || !(p = xdr_decode_string_inplace(p, &lock->caller,
324                                             &lock->len, NLM_MAXSTRLEN))
325          || !(p = nlm_decode_fh(p, &lock->fh))
326          || !(p = nlm_decode_oh(p, &lock->oh)))
327                 return 0;
328         argp->fsm_mode = ntohl(*p++);
329         argp->fsm_access = ntohl(*p++);
330         return xdr_argsize_check(rqstp, p);
331 }
332
333 int
334 nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
335 {
336         struct nlm_res *resp = rqstp->rq_resp;
337
338         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
339                 return 0;
340         *p++ = resp->status;
341         *p++ = xdr_zero;                /* sequence argument */
342         return xdr_ressize_check(rqstp, p);
343 }
344
345 int
346 nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
347 {
348         struct nlm_res *resp = rqstp->rq_resp;
349
350         if (!(p = nlm_encode_cookie(p, &resp->cookie)))
351                 return 0;
352         *p++ = resp->status;
353         return xdr_ressize_check(rqstp, p);
354 }
355
356 int
357 nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
358 {
359         struct nlm_args *argp = rqstp->rq_argp;
360         struct nlm_lock *lock = &argp->lock;
361
362         if (!(p = xdr_decode_string_inplace(p, &lock->caller,
363                                             &lock->len, NLM_MAXSTRLEN)))
364                 return 0;
365         argp->state = ntohl(*p++);
366         return xdr_argsize_check(rqstp, p);
367 }
368
369 int
370 nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
371 {
372         struct nlm_reboot *argp = rqstp->rq_argp;
373
374         if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
375                 return 0;
376         argp->state = ntohl(*p++);
377         memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
378         p += XDR_QUADLEN(SM_PRIV_SIZE);
379         return xdr_argsize_check(rqstp, p);
380 }
381
382 int
383 nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
384 {
385         struct nlm_res *resp = rqstp->rq_argp;
386
387         if (!(p = nlm_decode_cookie(p, &resp->cookie)))
388                 return 0;
389         resp->status = *p++;
390         return xdr_argsize_check(rqstp, p);
391 }
392
393 int
394 nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
395 {
396         return xdr_ressize_check(rqstp, p);
397 }