lockd: Update the NLMv1 TEST results encoder 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
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 */
52921e02
AV
47static inline __be32 *
48nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
1da177e4
LT
49{
50 *p++ = htonl(c->len);
51 memcpy(p, c->data, c->len);
52 p+=XDR_QUADLEN(c->len);
53 return p;
54}
55
2fd0c67a
CL
56/*
57 * NLM file handles are defined by specification to be a variable-length
58 * XDR opaque no longer than 1024 bytes. However, this implementation
59 * constrains their length to exactly the length of an NFSv2 file
60 * handle.
61 */
62static bool
63svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
64{
65 __be32 *p;
66 u32 len;
67
68 if (xdr_stream_decode_u32(xdr, &len) < 0)
69 return false;
70 if (len != NFS2_FHSIZE)
71 return false;
72
73 p = xdr_inline_decode(xdr, len);
74 if (!p)
75 return false;
76 fh->size = NFS2_FHSIZE;
77 memcpy(fh->data, p, len);
78 memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
79
80 return true;
81}
82
2fd0c67a
CL
83static bool
84svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
85{
86 struct file_lock *fl = &lock->fl;
87 s32 start, len, end;
88
89 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
90 return false;
91 if (!svcxdr_decode_fhandle(xdr, &lock->fh))
92 return false;
93 if (!svcxdr_decode_owner(xdr, &lock->oh))
94 return false;
95 if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
96 return false;
97 if (xdr_stream_decode_u32(xdr, &start) < 0)
98 return false;
99 if (xdr_stream_decode_u32(xdr, &len) < 0)
100 return false;
101
102 locks_init_lock(fl);
103 fl->fl_flags = FL_POSIX;
104 fl->fl_type = F_RDLCK;
105 end = start + len - 1;
106 fl->fl_start = s32_to_loff_t(start);
107 if (len == 0 || end < 0)
108 fl->fl_end = OFFSET_MAX;
109 else
110 fl->fl_end = s32_to_loff_t(end);
111
112 return true;
113}
114
adf98a48
CL
115static bool
116svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
1da177e4 117{
adf98a48
CL
118 const struct file_lock *fl = &lock->fl;
119 s32 start, len;
1da177e4 120
adf98a48
CL
121 /* exclusive */
122 if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
123 return false;
124 if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
125 return false;
126 if (!svcxdr_encode_owner(xdr, &lock->oh))
127 return false;
128 start = loff_t_to_s32(fl->fl_start);
129 if (fl->fl_end == OFFSET_MAX)
130 len = 0;
131 else
132 len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
133 if (xdr_stream_encode_u32(xdr, start) < 0)
134 return false;
135 if (xdr_stream_encode_u32(xdr, len) < 0)
136 return false;
1da177e4 137
adf98a48
CL
138 return true;
139}
1da177e4 140
adf98a48
CL
141static bool
142svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
143{
144 if (!svcxdr_encode_stats(xdr, resp->status))
145 return false;
146 switch (resp->status) {
147 case nlm_lck_denied:
148 if (!svcxdr_encode_holder(xdr, &resp->lock))
149 return false;
1da177e4
LT
150 }
151
adf98a48 152 return true;
1da177e4
LT
153}
154
155
156/*
cc1029b5 157 * Decode Call arguments
1da177e4 158 */
cc1029b5
CL
159
160int
161nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
162{
163 return 1;
164}
165
1da177e4 166int
026fec7e 167nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 168{
2fd0c67a 169 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
026fec7e 170 struct nlm_args *argp = rqstp->rq_argp;
2fd0c67a 171 u32 exclusive;
1da177e4 172
2fd0c67a 173 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
1da177e4 174 return 0;
2fd0c67a
CL
175 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
176 return 0;
177 if (!svcxdr_decode_lock(xdr, &argp->lock))
1da177e4
LT
178 return 0;
179 if (exclusive)
180 argp->lock.fl.fl_type = F_WRLCK;
181
2fd0c67a 182 return 1;
1da177e4
LT
183}
184
1da177e4 185int
026fec7e 186nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 187{
c1adb8c6 188 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
026fec7e 189 struct nlm_args *argp = rqstp->rq_argp;
c1adb8c6 190 u32 exclusive;
1da177e4 191
c1adb8c6 192 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
1da177e4 193 return 0;
c1adb8c6
CL
194 if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
195 return 0;
196 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
197 return 0;
198 if (!svcxdr_decode_lock(xdr, &argp->lock))
1da177e4
LT
199 return 0;
200 if (exclusive)
201 argp->lock.fl.fl_type = F_WRLCK;
c1adb8c6
CL
202 if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
203 return 0;
204 if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
205 return 0;
1da177e4
LT
206 argp->monitor = 1; /* monitor client by default */
207
c1adb8c6
CL
208 return 1;
209}
210
211int
f4e08f3a 212nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
c1adb8c6 213{
f4e08f3a
CL
214 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
215 struct nlm_args *argp = rqstp->rq_argp;
216 u32 exclusive;
c1adb8c6 217
f4e08f3a 218 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
c1adb8c6 219 return 0;
f4e08f3a
CL
220 if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
221 return 0;
222 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
223 return 0;
224 if (!svcxdr_decode_lock(xdr, &argp->lock))
225 return 0;
226 if (exclusive)
227 argp->lock.fl.fl_type = F_WRLCK;
228
229 return 1;
1da177e4
LT
230}
231
232int
c27045d3 233nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 234{
c27045d3
CL
235 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
236 struct nlm_args *argp = rqstp->rq_argp;
1da177e4 237
c27045d3 238 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
1da177e4 239 return 0;
c27045d3
CL
240 if (!svcxdr_decode_lock(xdr, &argp->lock))
241 return 0;
242 argp->lock.fl.fl_type = F_UNLCK;
243
244 return 1;
1da177e4
LT
245}
246
16ddcabe
CL
247int
248nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
249{
250 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
251 struct nlm_res *resp = rqstp->rq_argp;
252
253 if (!svcxdr_decode_cookie(xdr, &resp->cookie))
254 return 0;
255 if (!svcxdr_decode_stats(xdr, &resp->status))
256 return 0;
257
258 return 1;
259}
260
137e05e2
CL
261int
262nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
263{
264 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
265 struct nlm_reboot *argp = rqstp->rq_argp;
266 u32 len;
267
268 if (xdr_stream_decode_u32(xdr, &len) < 0)
269 return 0;
270 if (len > SM_MAXSTRLEN)
271 return 0;
272 p = xdr_inline_decode(xdr, len);
273 if (!p)
274 return 0;
275 argp->len = len;
276 argp->mon = (char *)p;
277 if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
278 return 0;
279 p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
280 if (!p)
281 return 0;
282 memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
283
284 return 1;
285}
286
1da177e4 287int
026fec7e 288nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
1da177e4 289{
890939e1 290 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
026fec7e 291 struct nlm_args *argp = rqstp->rq_argp;
1da177e4
LT
292 struct nlm_lock *lock = &argp->lock;
293
294 memset(lock, 0, sizeof(*lock));
295 locks_init_lock(&lock->fl);
890939e1 296 lock->svid = ~(u32)0;
1da177e4 297
890939e1 298 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
1da177e4 299 return 0;
890939e1
CL
300 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
301 return 0;
302 if (!svcxdr_decode_fhandle(xdr, &lock->fh))
303 return 0;
304 if (!svcxdr_decode_owner(xdr, &lock->oh))
305 return 0;
306 /* XXX: Range checks are missing in the original code */
307 if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
308 return 0;
309 if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
310 return 0;
311
312 return 1;
313}
314
14e10525
CL
315int
316nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
317{
318 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
319 struct nlm_args *argp = rqstp->rq_argp;
320 struct nlm_lock *lock = &argp->lock;
321
322 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
323 return 0;
324 if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
325 return 0;
326
327 return 1;
328}
329
e26ec898
CL
330
331/*
332 * Encode Reply results
333 */
334
335int
336nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
337{
338 return 1;
339}
340
890939e1
CL
341int
342nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
343{
adf98a48 344 struct xdr_stream *xdr = &rqstp->rq_res_stream;
890939e1
CL
345 struct nlm_res *resp = rqstp->rq_resp;
346
adf98a48
CL
347 return svcxdr_encode_cookie(xdr, &resp->cookie) &&
348 svcxdr_encode_testrply(xdr, resp);
1da177e4
LT
349}
350
351int
63f8de37 352nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
1da177e4 353{
63f8de37
CH
354 struct nlm_res *resp = rqstp->rq_resp;
355
1da177e4
LT
356 if (!(p = nlm_encode_cookie(p, &resp->cookie)))
357 return 0;
358 *p++ = resp->status;
359 *p++ = xdr_zero; /* sequence argument */
360 return xdr_ressize_check(rqstp, p);
361}
362
363int
63f8de37 364nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
1da177e4 365{
63f8de37
CH
366 struct nlm_res *resp = rqstp->rq_resp;
367
1da177e4
LT
368 if (!(p = nlm_encode_cookie(p, &resp->cookie)))
369 return 0;
370 *p++ = resp->status;
371 return xdr_ressize_check(rqstp, p);
372}