]>
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 <[email protected]> | |
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 | ||
52921e02 AV |
143 | static __be32 * |
144 | nlm_decode_lock(__be32 *p, struct nlm_lock *lock) | |
1da177e4 LT |
145 | { |
146 | struct file_lock *fl = &lock->fl; | |
147 | s32 start, len, end; | |
148 | ||
149 | if (!(p = xdr_decode_string_inplace(p, &lock->caller, | |
150 | &lock->len, | |
151 | NLM_MAXSTRLEN)) | |
152 | || !(p = nlm_decode_fh(p, &lock->fh)) | |
153 | || !(p = nlm_decode_oh(p, &lock->oh))) | |
154 | return NULL; | |
7bab377f | 155 | lock->svid = ntohl(*p++); |
1da177e4 LT |
156 | |
157 | locks_init_lock(fl); | |
1da177e4 LT |
158 | fl->fl_flags = FL_POSIX; |
159 | fl->fl_type = F_RDLCK; /* as good as anything else */ | |
160 | start = ntohl(*p++); | |
161 | len = ntohl(*p++); | |
162 | end = start + len - 1; | |
163 | ||
164 | fl->fl_start = s32_to_loff_t(start); | |
165 | ||
166 | if (len == 0 || end < 0) | |
167 | fl->fl_end = OFFSET_MAX; | |
168 | else | |
169 | fl->fl_end = s32_to_loff_t(end); | |
170 | return p; | |
171 | } | |
172 | ||
2fd0c67a CL |
173 | static bool |
174 | svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) | |
175 | { | |
176 | struct file_lock *fl = &lock->fl; | |
177 | s32 start, len, end; | |
178 | ||
179 | if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) | |
180 | return false; | |
181 | if (!svcxdr_decode_fhandle(xdr, &lock->fh)) | |
182 | return false; | |
183 | if (!svcxdr_decode_owner(xdr, &lock->oh)) | |
184 | return false; | |
185 | if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) | |
186 | return false; | |
187 | if (xdr_stream_decode_u32(xdr, &start) < 0) | |
188 | return false; | |
189 | if (xdr_stream_decode_u32(xdr, &len) < 0) | |
190 | return false; | |
191 | ||
192 | locks_init_lock(fl); | |
193 | fl->fl_flags = FL_POSIX; | |
194 | fl->fl_type = F_RDLCK; | |
195 | end = start + len - 1; | |
196 | fl->fl_start = s32_to_loff_t(start); | |
197 | if (len == 0 || end < 0) | |
198 | fl->fl_end = OFFSET_MAX; | |
199 | else | |
200 | fl->fl_end = s32_to_loff_t(end); | |
201 | ||
202 | return true; | |
203 | } | |
204 | ||
1da177e4 LT |
205 | /* |
206 | * Encode result of a TEST/TEST_MSG call | |
207 | */ | |
52921e02 AV |
208 | static __be32 * |
209 | nlm_encode_testres(__be32 *p, struct nlm_res *resp) | |
1da177e4 LT |
210 | { |
211 | s32 start, len; | |
212 | ||
213 | if (!(p = nlm_encode_cookie(p, &resp->cookie))) | |
214 | return NULL; | |
215 | *p++ = resp->status; | |
216 | ||
217 | if (resp->status == nlm_lck_denied) { | |
218 | struct file_lock *fl = &resp->lock.fl; | |
219 | ||
220 | *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; | |
7bab377f | 221 | *p++ = htonl(resp->lock.svid); |
1da177e4 LT |
222 | |
223 | /* Encode owner handle. */ | |
224 | if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) | |
225 | return NULL; | |
226 | ||
227 | start = loff_t_to_s32(fl->fl_start); | |
228 | if (fl->fl_end == OFFSET_MAX) | |
229 | len = 0; | |
230 | else | |
231 | len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); | |
232 | ||
233 | *p++ = htonl(start); | |
234 | *p++ = htonl(len); | |
235 | } | |
236 | ||
237 | return p; | |
238 | } | |
239 | ||
240 | ||
241 | /* | |
cc1029b5 | 242 | * Decode Call arguments |
1da177e4 | 243 | */ |
cc1029b5 CL |
244 | |
245 | int | |
246 | nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) | |
247 | { | |
248 | return 1; | |
249 | } | |
250 | ||
1da177e4 | 251 | int |
026fec7e | 252 | nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 253 | { |
2fd0c67a | 254 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; |
026fec7e | 255 | struct nlm_args *argp = rqstp->rq_argp; |
2fd0c67a | 256 | u32 exclusive; |
1da177e4 | 257 | |
2fd0c67a | 258 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
1da177e4 | 259 | return 0; |
2fd0c67a CL |
260 | if (xdr_stream_decode_bool(xdr, &exclusive) < 0) |
261 | return 0; | |
262 | if (!svcxdr_decode_lock(xdr, &argp->lock)) | |
1da177e4 LT |
263 | return 0; |
264 | if (exclusive) | |
265 | argp->lock.fl.fl_type = F_WRLCK; | |
266 | ||
2fd0c67a | 267 | return 1; |
1da177e4 LT |
268 | } |
269 | ||
270 | int | |
63f8de37 | 271 | nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 272 | { |
63f8de37 CH |
273 | struct nlm_res *resp = rqstp->rq_resp; |
274 | ||
1da177e4 LT |
275 | if (!(p = nlm_encode_testres(p, resp))) |
276 | return 0; | |
277 | return xdr_ressize_check(rqstp, p); | |
278 | } | |
279 | ||
280 | int | |
026fec7e | 281 | nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 282 | { |
026fec7e | 283 | struct nlm_args *argp = rqstp->rq_argp; |
1da177e4 LT |
284 | u32 exclusive; |
285 | ||
286 | if (!(p = nlm_decode_cookie(p, &argp->cookie))) | |
287 | return 0; | |
288 | argp->block = ntohl(*p++); | |
289 | exclusive = ntohl(*p++); | |
290 | if (!(p = nlm_decode_lock(p, &argp->lock))) | |
291 | return 0; | |
292 | if (exclusive) | |
293 | argp->lock.fl.fl_type = F_WRLCK; | |
294 | argp->reclaim = ntohl(*p++); | |
295 | argp->state = ntohl(*p++); | |
296 | argp->monitor = 1; /* monitor client by default */ | |
297 | ||
298 | return xdr_argsize_check(rqstp, p); | |
299 | } | |
300 | ||
301 | int | |
026fec7e | 302 | nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 303 | { |
026fec7e | 304 | struct nlm_args *argp = rqstp->rq_argp; |
1da177e4 LT |
305 | u32 exclusive; |
306 | ||
307 | if (!(p = nlm_decode_cookie(p, &argp->cookie))) | |
308 | return 0; | |
309 | argp->block = ntohl(*p++); | |
310 | exclusive = ntohl(*p++); | |
311 | if (!(p = nlm_decode_lock(p, &argp->lock))) | |
312 | return 0; | |
313 | if (exclusive) | |
314 | argp->lock.fl.fl_type = F_WRLCK; | |
315 | return xdr_argsize_check(rqstp, p); | |
316 | } | |
317 | ||
318 | int | |
026fec7e | 319 | nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 320 | { |
026fec7e CH |
321 | struct nlm_args *argp = rqstp->rq_argp; |
322 | ||
1da177e4 LT |
323 | if (!(p = nlm_decode_cookie(p, &argp->cookie)) |
324 | || !(p = nlm_decode_lock(p, &argp->lock))) | |
325 | return 0; | |
326 | argp->lock.fl.fl_type = F_UNLCK; | |
327 | return xdr_argsize_check(rqstp, p); | |
328 | } | |
329 | ||
330 | int | |
026fec7e | 331 | nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 332 | { |
026fec7e | 333 | struct nlm_args *argp = rqstp->rq_argp; |
1da177e4 LT |
334 | struct nlm_lock *lock = &argp->lock; |
335 | ||
336 | memset(lock, 0, sizeof(*lock)); | |
337 | locks_init_lock(&lock->fl); | |
7bab377f | 338 | lock->svid = ~(u32) 0; |
1da177e4 LT |
339 | |
340 | if (!(p = nlm_decode_cookie(p, &argp->cookie)) | |
341 | || !(p = xdr_decode_string_inplace(p, &lock->caller, | |
342 | &lock->len, NLM_MAXSTRLEN)) | |
343 | || !(p = nlm_decode_fh(p, &lock->fh)) | |
344 | || !(p = nlm_decode_oh(p, &lock->oh))) | |
345 | return 0; | |
346 | argp->fsm_mode = ntohl(*p++); | |
347 | argp->fsm_access = ntohl(*p++); | |
348 | return xdr_argsize_check(rqstp, p); | |
349 | } | |
350 | ||
351 | int | |
63f8de37 | 352 | nlmsvc_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 | ||
363 | int | |
63f8de37 | 364 | nlmsvc_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 | } | |
373 | ||
374 | int | |
026fec7e | 375 | nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 376 | { |
026fec7e | 377 | struct nlm_args *argp = rqstp->rq_argp; |
1da177e4 LT |
378 | struct nlm_lock *lock = &argp->lock; |
379 | ||
380 | if (!(p = xdr_decode_string_inplace(p, &lock->caller, | |
381 | &lock->len, NLM_MAXSTRLEN))) | |
382 | return 0; | |
383 | argp->state = ntohl(*p++); | |
384 | return xdr_argsize_check(rqstp, p); | |
385 | } | |
386 | ||
387 | int | |
026fec7e | 388 | nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 389 | { |
026fec7e CH |
390 | struct nlm_reboot *argp = rqstp->rq_argp; |
391 | ||
1da177e4 LT |
392 | if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) |
393 | return 0; | |
394 | argp->state = ntohl(*p++); | |
576df463 CL |
395 | memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); |
396 | p += XDR_QUADLEN(SM_PRIV_SIZE); | |
1da177e4 LT |
397 | return xdr_argsize_check(rqstp, p); |
398 | } | |
399 | ||
400 | int | |
026fec7e | 401 | nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 402 | { |
026fec7e CH |
403 | struct nlm_res *resp = rqstp->rq_argp; |
404 | ||
1da177e4 LT |
405 | if (!(p = nlm_decode_cookie(p, &resp->cookie))) |
406 | return 0; | |
e8c5c045 | 407 | resp->status = *p++; |
1da177e4 LT |
408 | return xdr_argsize_check(rqstp, p); |
409 | } | |
410 | ||
1da177e4 | 411 | int |
63f8de37 | 412 | nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 LT |
413 | { |
414 | return xdr_ressize_check(rqstp, p); | |
415 | } |