Commit | Line | Data |
---|---|---|
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 | ||
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 | */ | |
52921e02 | 49 | static __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 |
76 | static inline __be32 * |
77 | nlm_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 |
85 | static __be32 * |
86 | nlm_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 | */ | |
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 | ||
1da177e4 LT |
128 | /* |
129 | * Encode and decode owner handle | |
130 | */ | |
52921e02 AV |
131 | static inline __be32 * |
132 | nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) | |
1da177e4 LT |
133 | { |
134 | return xdr_decode_netobj(p, oh); | |
135 | } | |
136 | ||
52921e02 AV |
137 | static inline __be32 * |
138 | nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) | |
1da177e4 LT |
139 | { |
140 | return xdr_encode_netobj(p, oh); | |
141 | } | |
142 | ||
2fd0c67a CL |
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 | ||
1da177e4 LT |
175 | /* |
176 | * Encode result of a TEST/TEST_MSG call | |
177 | */ | |
52921e02 AV |
178 | static __be32 * |
179 | nlm_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 | |
215 | int | |
216 | nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) | |
217 | { | |
218 | return 1; | |
219 | } | |
220 | ||
1da177e4 | 221 | int |
026fec7e | 222 | nlmsvc_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 | 240 | int |
026fec7e | 241 | nlmsvc_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 | ||
266 | int | |
f4e08f3a | 267 | nlmsvc_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 | ||
287 | int | |
c27045d3 | 288 | nlmsvc_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 | ||
302 | int | |
c27045d3 | 303 | nlmsvc_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 | ||
312 | int | |
026fec7e | 313 | nlmsvc_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 | ||
333 | int | |
63f8de37 | 334 | nlmsvc_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 | ||
345 | int | |
63f8de37 | 346 | nlmsvc_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 | ||
356 | int | |
026fec7e | 357 | nlmsvc_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 | ||
369 | int | |
026fec7e | 370 | nlmsvc_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 | ||
382 | int | |
026fec7e | 383 | nlmsvc_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 | 393 | int |
63f8de37 | 394 | nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 LT |
395 | { |
396 | return xdr_ressize_check(rqstp, p); | |
397 | } |