lockd: Update the NLMv1 UNLOCK arguments decoder to use struct xdr_stream
[linux-block.git] / fs / lockd / xdr.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
1da177e4
LT
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
1da177e4
LT
10#include <linux/types.h>
11#include <linux/sched.h>
1da177e4
LT
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>
1da177e4 19
9c69de4c
CH
20#include <uapi/linux/nfs2.h>
21
cc1029b5
CL
22#include "svcxdr.h"
23
1da177e4
LT
24#define NLMDBG_FACILITY NLMDBG_XDR
25
26
27static inline loff_t
28s32_to_loff_t(__s32 offset)
29{
30 return (loff_t)offset;
31}
32
33static inline __s32
34loff_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 */
52921e02 49static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
1da177e4
LT
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 {
e159a08b
CL
68 dprintk("lockd: bad cookie size %d (only cookies under "
69 "%d bytes are supported.)\n",
70 len, NLM_MAXCOOKIELEN);
1da177e4
LT
71 return NULL;
72 }
73 return p;
74}
75
52921e02
AV
76static inline __be32 *
77nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
1da177e4
LT
78{
79 *p++ = htonl(c->len);
80 memcpy(p, c->data, c->len);
81 p+=XDR_QUADLEN(c->len);
82 return p;
83}
84
52921e02
AV
85static __be32 *
86nlm_decode_fh(__be32 *p, struct nfs_fh *f)
1da177e4
LT
87{
88 unsigned int len;
89
90 if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
e159a08b 91 dprintk("lockd: bad fhandle size %d (should be %d)\n",
1da177e4
LT
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
2fd0c67a
CL
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 */
107static bool
108svcxdr_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
1da177e4
LT
128/*
129 * Encode and decode owner handle
130 */
52921e02
AV
131static inline __be32 *
132nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
1da177e4
LT
133{
134 return xdr_decode_netobj(p, oh);
135}
136
52921e02
AV
137static inline __be32 *
138nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
1da177e4
LT
139{
140 return xdr_encode_netobj(p, oh);
141}
142
2fd0c67a
CL
143static bool
144svcxdr_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
1da177e4
LT
175/*
176 * Encode result of a TEST/TEST_MSG call
177 */
52921e02
AV
178static __be32 *
179nlm_encode_testres(__be32 *p, struct nlm_res *resp)
1da177e4
LT
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;
7bab377f 191 *p++ = htonl(resp->lock.svid);
1da177e4
LT
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/*
cc1029b5 212 * Decode Call arguments
1da177e4 213 */
cc1029b5
CL
214
215int
216nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
217{
218 return 1;
219}
220
1da177e4 221int
026fec7e 222nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 223{
2fd0c67a 224 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
026fec7e 225 struct nlm_args *argp = rqstp->rq_argp;
2fd0c67a 226 u32 exclusive;
1da177e4 227
2fd0c67a 228 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
1da177e4 229 return 0;
2fd0c67a
CL
230 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
231 return 0;
232 if (!svcxdr_decode_lock(xdr, &argp->lock))
1da177e4
LT
233 return 0;
234 if (exclusive)
235 argp->lock.fl.fl_type = F_WRLCK;
236
2fd0c67a 237 return 1;
1da177e4
LT
238}
239
1da177e4 240int
026fec7e 241nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 242{
c1adb8c6 243 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
026fec7e 244 struct nlm_args *argp = rqstp->rq_argp;
c1adb8c6 245 u32 exclusive;
1da177e4 246
c1adb8c6 247 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
1da177e4 248 return 0;
c1adb8c6
CL
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))
1da177e4
LT
254 return 0;
255 if (exclusive)
256 argp->lock.fl.fl_type = F_WRLCK;
c1adb8c6
CL
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;
1da177e4
LT
261 argp->monitor = 1; /* monitor client by default */
262
c1adb8c6
CL
263 return 1;
264}
265
266int
f4e08f3a 267nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
c1adb8c6 268{
f4e08f3a
CL
269 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
270 struct nlm_args *argp = rqstp->rq_argp;
271 u32 exclusive;
c1adb8c6 272
f4e08f3a 273 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
c1adb8c6 274 return 0;
f4e08f3a
CL
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;
1da177e4
LT
285}
286
287int
c27045d3 288nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 289{
c27045d3
CL
290 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
291 struct nlm_args *argp = rqstp->rq_argp;
1da177e4 292
c27045d3 293 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
1da177e4 294 return 0;
c27045d3
CL
295 if (!svcxdr_decode_lock(xdr, &argp->lock))
296 return 0;
297 argp->lock.fl.fl_type = F_UNLCK;
298
299 return 1;
1da177e4
LT
300}
301
302int
c27045d3 303nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
1da177e4 304{
c27045d3 305 struct nlm_res *resp = rqstp->rq_resp;
026fec7e 306
c27045d3 307 if (!(p = nlm_encode_testres(p, resp)))
1da177e4 308 return 0;
c27045d3 309 return xdr_ressize_check(rqstp, p);
1da177e4
LT
310}
311
312int
026fec7e 313nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 314{
026fec7e 315 struct nlm_args *argp = rqstp->rq_argp;
1da177e4
LT
316 struct nlm_lock *lock = &argp->lock;
317
318 memset(lock, 0, sizeof(*lock));
319 locks_init_lock(&lock->fl);
7bab377f 320 lock->svid = ~(u32) 0;
1da177e4
LT
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
333int
63f8de37 334nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
1da177e4 335{
63f8de37
CH
336 struct nlm_res *resp = rqstp->rq_resp;
337
1da177e4
LT
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
345int
63f8de37 346nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
1da177e4 347{
63f8de37
CH
348 struct nlm_res *resp = rqstp->rq_resp;
349
1da177e4
LT
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
356int
026fec7e 357nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
1da177e4 358{
026fec7e 359 struct nlm_args *argp = rqstp->rq_argp;
1da177e4
LT
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
369int
026fec7e 370nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
1da177e4 371{
026fec7e
CH
372 struct nlm_reboot *argp = rqstp->rq_argp;
373
1da177e4
LT
374 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
375 return 0;
376 argp->state = ntohl(*p++);
576df463
CL
377 memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
378 p += XDR_QUADLEN(SM_PRIV_SIZE);
1da177e4
LT
379 return xdr_argsize_check(rqstp, p);
380}
381
382int
026fec7e 383nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
1da177e4 384{
026fec7e
CH
385 struct nlm_res *resp = rqstp->rq_argp;
386
1da177e4
LT
387 if (!(p = nlm_decode_cookie(p, &resp->cookie)))
388 return 0;
e8c5c045 389 resp->status = *p++;
1da177e4
LT
390 return xdr_argsize_check(rqstp, p);
391}
392
1da177e4 393int
63f8de37 394nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
1da177e4
LT
395{
396 return xdr_ressize_check(rqstp, p);
397}