]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | /* |
3 | * linux/fs/lockd/xdr4.c | |
4 | * | |
5 | * XDR support for lockd and the lock client. | |
6 | * | |
7 | * Copyright (C) 1995, 1996 Olaf Kirch <[email protected]> | |
8 | * Copyright (C) 1999, Trond Myklebust <[email protected]> | |
9 | */ | |
10 | ||
11 | #include <linux/types.h> | |
12 | #include <linux/sched.h> | |
1da177e4 LT |
13 | #include <linux/nfs.h> |
14 | ||
15 | #include <linux/sunrpc/xdr.h> | |
16 | #include <linux/sunrpc/clnt.h> | |
17 | #include <linux/sunrpc/svc.h> | |
18 | #include <linux/sunrpc/stats.h> | |
19 | #include <linux/lockd/lockd.h> | |
1da177e4 | 20 | |
7956521a CL |
21 | #include "svcxdr.h" |
22 | ||
1da177e4 LT |
23 | static inline loff_t |
24 | s64_to_loff_t(__s64 offset) | |
25 | { | |
26 | return (loff_t)offset; | |
27 | } | |
28 | ||
29 | ||
30 | static inline s64 | |
31 | loff_t_to_s64(loff_t offset) | |
32 | { | |
33 | s64 res; | |
34 | if (offset > NLM4_OFFSET_MAX) | |
35 | res = NLM4_OFFSET_MAX; | |
36 | else if (offset < -NLM4_OFFSET_MAX) | |
37 | res = -NLM4_OFFSET_MAX; | |
38 | else | |
39 | res = offset; | |
40 | return res; | |
41 | } | |
42 | ||
345b4159 CL |
43 | /* |
44 | * NLM file handles are defined by specification to be a variable-length | |
45 | * XDR opaque no longer than 1024 bytes. However, this implementation | |
46 | * limits their length to the size of an NFSv3 file handle. | |
47 | */ | |
48 | static bool | |
49 | svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) | |
50 | { | |
51 | __be32 *p; | |
52 | u32 len; | |
53 | ||
54 | if (xdr_stream_decode_u32(xdr, &len) < 0) | |
55 | return false; | |
56 | if (len > NFS_MAXFHSIZE) | |
57 | return false; | |
58 | ||
59 | p = xdr_inline_decode(xdr, len); | |
60 | if (!p) | |
61 | return false; | |
62 | fh->size = len; | |
63 | memcpy(fh->data, p, len); | |
64 | memset(fh->data + len, 0, sizeof(fh->data) - len); | |
65 | ||
66 | return true; | |
67 | } | |
68 | ||
345b4159 CL |
69 | static bool |
70 | svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) | |
71 | { | |
72 | struct file_lock *fl = &lock->fl; | |
73 | u64 len, start; | |
74 | s64 end; | |
75 | ||
76 | if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) | |
77 | return false; | |
78 | if (!svcxdr_decode_fhandle(xdr, &lock->fh)) | |
79 | return false; | |
80 | if (!svcxdr_decode_owner(xdr, &lock->oh)) | |
81 | return false; | |
82 | if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) | |
83 | return false; | |
84 | if (xdr_stream_decode_u64(xdr, &start) < 0) | |
85 | return false; | |
86 | if (xdr_stream_decode_u64(xdr, &len) < 0) | |
87 | return false; | |
88 | ||
89 | locks_init_lock(fl); | |
90 | fl->fl_flags = FL_POSIX; | |
91 | fl->fl_type = F_RDLCK; | |
92 | end = start + len - 1; | |
93 | fl->fl_start = s64_to_loff_t(start); | |
94 | if (len == 0 || end < 0) | |
95 | fl->fl_end = OFFSET_MAX; | |
96 | else | |
97 | fl->fl_end = s64_to_loff_t(end); | |
98 | ||
99 | return true; | |
100 | } | |
101 | ||
1beef147 CL |
102 | static bool |
103 | svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) | |
1da177e4 | 104 | { |
1beef147 CL |
105 | const struct file_lock *fl = &lock->fl; |
106 | s64 start, len; | |
1da177e4 | 107 | |
1beef147 CL |
108 | /* exclusive */ |
109 | if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) | |
110 | return false; | |
111 | if (xdr_stream_encode_u32(xdr, lock->svid) < 0) | |
112 | return false; | |
113 | if (!svcxdr_encode_owner(xdr, &lock->oh)) | |
114 | return false; | |
115 | start = loff_t_to_s64(fl->fl_start); | |
116 | if (fl->fl_end == OFFSET_MAX) | |
117 | len = 0; | |
118 | else | |
119 | len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); | |
120 | if (xdr_stream_encode_u64(xdr, start) < 0) | |
121 | return false; | |
122 | if (xdr_stream_encode_u64(xdr, len) < 0) | |
123 | return false; | |
124 | ||
125 | return true; | |
126 | } | |
1da177e4 | 127 | |
1beef147 CL |
128 | static bool |
129 | svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) | |
130 | { | |
131 | if (!svcxdr_encode_stats(xdr, resp->status)) | |
132 | return false; | |
133 | switch (resp->status) { | |
134 | case nlm_lck_denied: | |
135 | if (!svcxdr_encode_holder(xdr, &resp->lock)) | |
136 | return false; | |
1da177e4 LT |
137 | } |
138 | ||
1beef147 | 139 | return true; |
1da177e4 LT |
140 | } |
141 | ||
142 | ||
143 | /* | |
7956521a | 144 | * Decode Call arguments |
1da177e4 | 145 | */ |
7956521a CL |
146 | |
147 | int | |
148 | nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) | |
149 | { | |
150 | return 1; | |
151 | } | |
152 | ||
1da177e4 | 153 | int |
026fec7e | 154 | nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 155 | { |
345b4159 | 156 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; |
026fec7e | 157 | struct nlm_args *argp = rqstp->rq_argp; |
345b4159 | 158 | u32 exclusive; |
1da177e4 | 159 | |
345b4159 | 160 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
1da177e4 | 161 | return 0; |
345b4159 CL |
162 | if (xdr_stream_decode_bool(xdr, &exclusive) < 0) |
163 | return 0; | |
164 | if (!svcxdr_decode_lock(xdr, &argp->lock)) | |
1da177e4 LT |
165 | return 0; |
166 | if (exclusive) | |
167 | argp->lock.fl.fl_type = F_WRLCK; | |
168 | ||
345b4159 | 169 | return 1; |
1da177e4 LT |
170 | } |
171 | ||
1da177e4 | 172 | int |
026fec7e | 173 | nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 174 | { |
0e5977af | 175 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; |
026fec7e | 176 | struct nlm_args *argp = rqstp->rq_argp; |
0e5977af | 177 | u32 exclusive; |
1da177e4 | 178 | |
0e5977af | 179 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
1da177e4 | 180 | return 0; |
0e5977af CL |
181 | if (xdr_stream_decode_bool(xdr, &argp->block) < 0) |
182 | return 0; | |
183 | if (xdr_stream_decode_bool(xdr, &exclusive) < 0) | |
184 | return 0; | |
185 | if (!svcxdr_decode_lock(xdr, &argp->lock)) | |
1da177e4 LT |
186 | return 0; |
187 | if (exclusive) | |
188 | argp->lock.fl.fl_type = F_WRLCK; | |
0e5977af CL |
189 | if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) |
190 | return 0; | |
191 | if (xdr_stream_decode_u32(xdr, &argp->state) < 0) | |
192 | return 0; | |
1da177e4 LT |
193 | argp->monitor = 1; /* monitor client by default */ |
194 | ||
0e5977af CL |
195 | return 1; |
196 | } | |
197 | ||
198 | int | |
1e1f38dc | 199 | nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) |
0e5977af | 200 | { |
1e1f38dc CL |
201 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; |
202 | struct nlm_args *argp = rqstp->rq_argp; | |
203 | u32 exclusive; | |
0e5977af | 204 | |
1e1f38dc | 205 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
0e5977af | 206 | return 0; |
1e1f38dc CL |
207 | if (xdr_stream_decode_bool(xdr, &argp->block) < 0) |
208 | return 0; | |
209 | if (xdr_stream_decode_bool(xdr, &exclusive) < 0) | |
210 | return 0; | |
211 | if (!svcxdr_decode_lock(xdr, &argp->lock)) | |
212 | return 0; | |
213 | if (exclusive) | |
214 | argp->lock.fl.fl_type = F_WRLCK; | |
215 | return 1; | |
1da177e4 LT |
216 | } |
217 | ||
218 | int | |
d76d8c25 | 219 | nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 220 | { |
d76d8c25 CL |
221 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; |
222 | struct nlm_args *argp = rqstp->rq_argp; | |
1da177e4 | 223 | |
d76d8c25 | 224 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
1da177e4 | 225 | return 0; |
d76d8c25 CL |
226 | if (!svcxdr_decode_lock(xdr, &argp->lock)) |
227 | return 0; | |
228 | argp->lock.fl.fl_type = F_UNLCK; | |
229 | ||
230 | return 1; | |
1da177e4 LT |
231 | } |
232 | ||
b4c24b5a CL |
233 | int |
234 | nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) | |
235 | { | |
236 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; | |
237 | struct nlm_res *resp = rqstp->rq_argp; | |
238 | ||
239 | if (!svcxdr_decode_cookie(xdr, &resp->cookie)) | |
240 | return 0; | |
241 | if (!svcxdr_decode_stats(xdr, &resp->status)) | |
242 | return 0; | |
243 | ||
244 | return 1; | |
245 | } | |
246 | ||
bc3665fd CL |
247 | int |
248 | nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) | |
249 | { | |
250 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; | |
251 | struct nlm_reboot *argp = rqstp->rq_argp; | |
252 | u32 len; | |
253 | ||
254 | if (xdr_stream_decode_u32(xdr, &len) < 0) | |
255 | return 0; | |
256 | if (len > SM_MAXSTRLEN) | |
257 | return 0; | |
258 | p = xdr_inline_decode(xdr, len); | |
259 | if (!p) | |
260 | return 0; | |
261 | argp->len = len; | |
262 | argp->mon = (char *)p; | |
263 | if (xdr_stream_decode_u32(xdr, &argp->state) < 0) | |
264 | return 0; | |
265 | p = xdr_inline_decode(xdr, SM_PRIV_SIZE); | |
266 | if (!p) | |
267 | return 0; | |
268 | memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); | |
269 | ||
270 | return 1; | |
271 | } | |
272 | ||
1da177e4 | 273 | int |
026fec7e | 274 | nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 275 | { |
7cf96b6d | 276 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; |
026fec7e | 277 | struct nlm_args *argp = rqstp->rq_argp; |
1da177e4 LT |
278 | struct nlm_lock *lock = &argp->lock; |
279 | ||
280 | memset(lock, 0, sizeof(*lock)); | |
281 | locks_init_lock(&lock->fl); | |
7cf96b6d | 282 | lock->svid = ~(u32)0; |
1da177e4 | 283 | |
7cf96b6d | 284 | if (!svcxdr_decode_cookie(xdr, &argp->cookie)) |
1da177e4 | 285 | return 0; |
7cf96b6d CL |
286 | if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) |
287 | return 0; | |
288 | if (!svcxdr_decode_fhandle(xdr, &lock->fh)) | |
289 | return 0; | |
290 | if (!svcxdr_decode_owner(xdr, &lock->oh)) | |
291 | return 0; | |
292 | /* XXX: Range checks are missing in the original code */ | |
293 | if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) | |
294 | return 0; | |
295 | if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) | |
296 | return 0; | |
297 | ||
298 | return 1; | |
299 | } | |
300 | ||
3049e974 CL |
301 | int |
302 | nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) | |
303 | { | |
304 | struct xdr_stream *xdr = &rqstp->rq_arg_stream; | |
305 | struct nlm_args *argp = rqstp->rq_argp; | |
306 | struct nlm_lock *lock = &argp->lock; | |
307 | ||
308 | if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) | |
309 | return 0; | |
310 | if (xdr_stream_decode_u32(xdr, &argp->state) < 0) | |
311 | return 0; | |
312 | ||
313 | return 1; | |
314 | } | |
315 | ||
ec757e42 CL |
316 | |
317 | /* | |
318 | * Encode Reply results | |
319 | */ | |
320 | ||
321 | int | |
322 | nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) | |
323 | { | |
324 | return 1; | |
325 | } | |
326 | ||
7cf96b6d CL |
327 | int |
328 | nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) | |
329 | { | |
1beef147 | 330 | struct xdr_stream *xdr = &rqstp->rq_res_stream; |
7cf96b6d CL |
331 | struct nlm_res *resp = rqstp->rq_resp; |
332 | ||
1beef147 CL |
333 | return svcxdr_encode_cookie(xdr, &resp->cookie) && |
334 | svcxdr_encode_testrply(xdr, resp); | |
1da177e4 LT |
335 | } |
336 | ||
337 | int | |
447c14d4 | 338 | nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 339 | { |
447c14d4 | 340 | struct xdr_stream *xdr = &rqstp->rq_res_stream; |
63f8de37 CH |
341 | struct nlm_res *resp = rqstp->rq_resp; |
342 | ||
447c14d4 CL |
343 | return svcxdr_encode_cookie(xdr, &resp->cookie) && |
344 | svcxdr_encode_stats(xdr, resp->status); | |
1da177e4 LT |
345 | } |
346 | ||
347 | int | |
447c14d4 | 348 | nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) |
1da177e4 | 349 | { |
0ff5b50a | 350 | struct xdr_stream *xdr = &rqstp->rq_res_stream; |
63f8de37 CH |
351 | struct nlm_res *resp = rqstp->rq_resp; |
352 | ||
0ff5b50a | 353 | if (!svcxdr_encode_cookie(xdr, &resp->cookie)) |
1da177e4 | 354 | return 0; |
0ff5b50a CL |
355 | if (!svcxdr_encode_stats(xdr, resp->status)) |
356 | return 0; | |
357 | /* sequence */ | |
358 | if (xdr_stream_encode_u32(xdr, 0) < 0) | |
359 | return 0; | |
360 | ||
361 | return 1; | |
1da177e4 | 362 | } |