Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * linux/fs/lockd/clntxdr.c
4 : : *
5 : : * XDR functions to encode/decode NLM version 3 RPC arguments and results.
6 : : * NLM version 3 is backwards compatible with NLM versions 1 and 2.
7 : : *
8 : : * NLM client-side only.
9 : : *
10 : : * Copyright (C) 2010, Oracle. All rights reserved.
11 : : */
12 : :
13 : : #include <linux/types.h>
14 : : #include <linux/sunrpc/xdr.h>
15 : : #include <linux/sunrpc/clnt.h>
16 : : #include <linux/sunrpc/stats.h>
17 : : #include <linux/lockd/lockd.h>
18 : :
19 : : #include <uapi/linux/nfs2.h>
20 : :
21 : : #define NLMDBG_FACILITY NLMDBG_XDR
22 : :
23 : : #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
24 : : # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
25 : : #endif
26 : :
27 : : /*
28 : : * Declare the space requirements for NLM arguments and replies as
29 : : * number of 32bit-words
30 : : */
31 : : #define NLM_cookie_sz (1+(NLM_MAXCOOKIELEN>>2))
32 : : #define NLM_caller_sz (1+(NLMCLNT_OHSIZE>>2))
33 : : #define NLM_owner_sz (1+(NLMCLNT_OHSIZE>>2))
34 : : #define NLM_fhandle_sz (1+(NFS2_FHSIZE>>2))
35 : : #define NLM_lock_sz (3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz)
36 : : #define NLM_holder_sz (4+NLM_owner_sz)
37 : :
38 : : #define NLM_testargs_sz (NLM_cookie_sz+1+NLM_lock_sz)
39 : : #define NLM_lockargs_sz (NLM_cookie_sz+4+NLM_lock_sz)
40 : : #define NLM_cancargs_sz (NLM_cookie_sz+2+NLM_lock_sz)
41 : : #define NLM_unlockargs_sz (NLM_cookie_sz+NLM_lock_sz)
42 : :
43 : : #define NLM_testres_sz (NLM_cookie_sz+1+NLM_holder_sz)
44 : : #define NLM_res_sz (NLM_cookie_sz+1)
45 : : #define NLM_norep_sz (0)
46 : :
47 : :
48 : : static s32 loff_t_to_s32(loff_t offset)
49 : : {
50 : : s32 res;
51 : :
52 : 0 : if (offset >= NLM_OFFSET_MAX)
53 : : res = NLM_OFFSET_MAX;
54 : 0 : else if (offset <= -NLM_OFFSET_MAX)
55 : : res = -NLM_OFFSET_MAX;
56 : : else
57 : 0 : res = offset;
58 : : return res;
59 : : }
60 : :
61 : 0 : static void nlm_compute_offsets(const struct nlm_lock *lock,
62 : : u32 *l_offset, u32 *l_len)
63 : : {
64 : : const struct file_lock *fl = &lock->fl;
65 : :
66 : 0 : *l_offset = loff_t_to_s32(fl->fl_start);
67 : 0 : if (fl->fl_end == OFFSET_MAX)
68 : 0 : *l_len = 0;
69 : : else
70 : 0 : *l_len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
71 : 0 : }
72 : :
73 : : /*
74 : : * Encode/decode NLMv3 basic data types
75 : : *
76 : : * Basic NLMv3 data types are not defined in an IETF standards
77 : : * document. X/Open has a description of these data types that
78 : : * is useful. See Chapter 10 of "Protocols for Interworking:
79 : : * XNFS, Version 3W".
80 : : *
81 : : * Not all basic data types have their own encoding and decoding
82 : : * functions. For run-time efficiency, some data types are encoded
83 : : * or decoded inline.
84 : : */
85 : :
86 : : static void encode_bool(struct xdr_stream *xdr, const int value)
87 : : {
88 : : __be32 *p;
89 : :
90 : 0 : p = xdr_reserve_space(xdr, 4);
91 : 0 : *p = value ? xdr_one : xdr_zero;
92 : : }
93 : :
94 : : static void encode_int32(struct xdr_stream *xdr, const s32 value)
95 : : {
96 : : __be32 *p;
97 : :
98 : 0 : p = xdr_reserve_space(xdr, 4);
99 : 0 : *p = cpu_to_be32(value);
100 : : }
101 : :
102 : : /*
103 : : * typedef opaque netobj<MAXNETOBJ_SZ>
104 : : */
105 : 0 : static void encode_netobj(struct xdr_stream *xdr,
106 : : const u8 *data, const unsigned int length)
107 : : {
108 : : __be32 *p;
109 : :
110 : 0 : p = xdr_reserve_space(xdr, 4 + length);
111 : 0 : xdr_encode_opaque(p, data, length);
112 : 0 : }
113 : :
114 : : static int decode_netobj(struct xdr_stream *xdr,
115 : : struct xdr_netobj *obj)
116 : : {
117 : : ssize_t ret;
118 : :
119 : 0 : ret = xdr_stream_decode_opaque_inline(xdr, (void *)&obj->data,
120 : : XDR_MAX_NETOBJ);
121 : 0 : if (unlikely(ret < 0))
122 : : return -EIO;
123 : 0 : obj->len = ret;
124 : : return 0;
125 : : }
126 : :
127 : : /*
128 : : * netobj cookie;
129 : : */
130 : : static void encode_cookie(struct xdr_stream *xdr,
131 : : const struct nlm_cookie *cookie)
132 : : {
133 : 0 : encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
134 : : }
135 : :
136 : 0 : static int decode_cookie(struct xdr_stream *xdr,
137 : : struct nlm_cookie *cookie)
138 : : {
139 : : u32 length;
140 : : __be32 *p;
141 : :
142 : 0 : p = xdr_inline_decode(xdr, 4);
143 : 0 : if (unlikely(p == NULL))
144 : : goto out_overflow;
145 : : length = be32_to_cpup(p++);
146 : : /* apparently HPUX can return empty cookies */
147 : 0 : if (length == 0)
148 : : goto out_hpux;
149 : 0 : if (length > NLM_MAXCOOKIELEN)
150 : : goto out_size;
151 : 0 : p = xdr_inline_decode(xdr, length);
152 : 0 : if (unlikely(p == NULL))
153 : : goto out_overflow;
154 : 0 : cookie->len = length;
155 : 0 : memcpy(cookie->data, p, length);
156 : 0 : return 0;
157 : : out_hpux:
158 : 0 : cookie->len = 4;
159 : 0 : memset(cookie->data, 0, 4);
160 : 0 : return 0;
161 : : out_size:
162 : : dprintk("NFS: returned cookie was too long: %u\n", length);
163 : : return -EIO;
164 : : out_overflow:
165 : : return -EIO;
166 : : }
167 : :
168 : : /*
169 : : * netobj fh;
170 : : */
171 : : static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
172 : : {
173 : 0 : encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE);
174 : : }
175 : :
176 : : /*
177 : : * enum nlm_stats {
178 : : * LCK_GRANTED = 0,
179 : : * LCK_DENIED = 1,
180 : : * LCK_DENIED_NOLOCKS = 2,
181 : : * LCK_BLOCKED = 3,
182 : : * LCK_DENIED_GRACE_PERIOD = 4
183 : : * };
184 : : *
185 : : *
186 : : * struct nlm_stat {
187 : : * nlm_stats stat;
188 : : * };
189 : : *
190 : : * NB: we don't swap bytes for the NLM status values. The upper
191 : : * layers deal directly with the status value in network byte
192 : : * order.
193 : : */
194 : :
195 : 0 : static void encode_nlm_stat(struct xdr_stream *xdr,
196 : : const __be32 stat)
197 : : {
198 : : __be32 *p;
199 : :
200 : 0 : WARN_ON_ONCE(be32_to_cpu(stat) > NLM_LCK_DENIED_GRACE_PERIOD);
201 : 0 : p = xdr_reserve_space(xdr, 4);
202 : 0 : *p = stat;
203 : 0 : }
204 : :
205 : 0 : static int decode_nlm_stat(struct xdr_stream *xdr,
206 : : __be32 *stat)
207 : : {
208 : : __be32 *p;
209 : :
210 : 0 : p = xdr_inline_decode(xdr, 4);
211 : 0 : if (unlikely(p == NULL))
212 : : goto out_overflow;
213 : 0 : if (unlikely(ntohl(*p) > ntohl(nlm_lck_denied_grace_period)))
214 : : goto out_enum;
215 : 0 : *stat = *p;
216 : 0 : return 0;
217 : : out_enum:
218 : : dprintk("%s: server returned invalid nlm_stats value: %u\n",
219 : : __func__, be32_to_cpup(p));
220 : : return -EIO;
221 : : out_overflow:
222 : : return -EIO;
223 : : }
224 : :
225 : : /*
226 : : * struct nlm_holder {
227 : : * bool exclusive;
228 : : * int uppid;
229 : : * netobj oh;
230 : : * unsigned l_offset;
231 : : * unsigned l_len;
232 : : * };
233 : : */
234 : 0 : static void encode_nlm_holder(struct xdr_stream *xdr,
235 : : const struct nlm_res *result)
236 : : {
237 : 0 : const struct nlm_lock *lock = &result->lock;
238 : : u32 l_offset, l_len;
239 : : __be32 *p;
240 : :
241 : 0 : encode_bool(xdr, lock->fl.fl_type == F_RDLCK);
242 : 0 : encode_int32(xdr, lock->svid);
243 : 0 : encode_netobj(xdr, lock->oh.data, lock->oh.len);
244 : :
245 : 0 : p = xdr_reserve_space(xdr, 4 + 4);
246 : 0 : nlm_compute_offsets(lock, &l_offset, &l_len);
247 : 0 : *p++ = cpu_to_be32(l_offset);
248 : 0 : *p = cpu_to_be32(l_len);
249 : 0 : }
250 : :
251 : 0 : static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
252 : : {
253 : 0 : struct nlm_lock *lock = &result->lock;
254 : 0 : struct file_lock *fl = &lock->fl;
255 : : u32 exclusive, l_offset, l_len;
256 : : int error;
257 : : __be32 *p;
258 : : s32 end;
259 : :
260 : 0 : memset(lock, 0, sizeof(*lock));
261 : 0 : locks_init_lock(fl);
262 : :
263 : 0 : p = xdr_inline_decode(xdr, 4 + 4);
264 : 0 : if (unlikely(p == NULL))
265 : : goto out_overflow;
266 : : exclusive = be32_to_cpup(p++);
267 : 0 : lock->svid = be32_to_cpup(p);
268 : 0 : fl->fl_pid = (pid_t)lock->svid;
269 : :
270 : : error = decode_netobj(xdr, &lock->oh);
271 : 0 : if (unlikely(error))
272 : : goto out;
273 : :
274 : 0 : p = xdr_inline_decode(xdr, 4 + 4);
275 : 0 : if (unlikely(p == NULL))
276 : : goto out_overflow;
277 : :
278 : 0 : fl->fl_flags = FL_POSIX;
279 : 0 : fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK;
280 : : l_offset = be32_to_cpup(p++);
281 : : l_len = be32_to_cpup(p);
282 : 0 : end = l_offset + l_len - 1;
283 : :
284 : 0 : fl->fl_start = (loff_t)l_offset;
285 : 0 : if (l_len == 0 || end < 0)
286 : 0 : fl->fl_end = OFFSET_MAX;
287 : : else
288 : 0 : fl->fl_end = (loff_t)end;
289 : : error = 0;
290 : : out:
291 : 0 : return error;
292 : : out_overflow:
293 : : return -EIO;
294 : : }
295 : :
296 : : /*
297 : : * string caller_name<LM_MAXSTRLEN>;
298 : : */
299 : 0 : static void encode_caller_name(struct xdr_stream *xdr, const char *name)
300 : : {
301 : : /* NB: client-side does not set lock->len */
302 : 0 : u32 length = strlen(name);
303 : : __be32 *p;
304 : :
305 : 0 : p = xdr_reserve_space(xdr, 4 + length);
306 : 0 : xdr_encode_opaque(p, name, length);
307 : 0 : }
308 : :
309 : : /*
310 : : * struct nlm_lock {
311 : : * string caller_name<LM_MAXSTRLEN>;
312 : : * netobj fh;
313 : : * netobj oh;
314 : : * int uppid;
315 : : * unsigned l_offset;
316 : : * unsigned l_len;
317 : : * };
318 : : */
319 : 0 : static void encode_nlm_lock(struct xdr_stream *xdr,
320 : : const struct nlm_lock *lock)
321 : : {
322 : : u32 l_offset, l_len;
323 : : __be32 *p;
324 : :
325 : 0 : encode_caller_name(xdr, lock->caller);
326 : : encode_fh(xdr, &lock->fh);
327 : 0 : encode_netobj(xdr, lock->oh.data, lock->oh.len);
328 : :
329 : 0 : p = xdr_reserve_space(xdr, 4 + 4 + 4);
330 : 0 : *p++ = cpu_to_be32(lock->svid);
331 : :
332 : 0 : nlm_compute_offsets(lock, &l_offset, &l_len);
333 : 0 : *p++ = cpu_to_be32(l_offset);
334 : 0 : *p = cpu_to_be32(l_len);
335 : 0 : }
336 : :
337 : :
338 : : /*
339 : : * NLMv3 XDR encode functions
340 : : *
341 : : * NLMv3 argument types are defined in Chapter 10 of The Open Group's
342 : : * "Protocols for Interworking: XNFS, Version 3W".
343 : : */
344 : :
345 : : /*
346 : : * struct nlm_testargs {
347 : : * netobj cookie;
348 : : * bool exclusive;
349 : : * struct nlm_lock alock;
350 : : * };
351 : : */
352 : 0 : static void nlm_xdr_enc_testargs(struct rpc_rqst *req,
353 : : struct xdr_stream *xdr,
354 : : const void *data)
355 : : {
356 : : const struct nlm_args *args = data;
357 : 0 : const struct nlm_lock *lock = &args->lock;
358 : :
359 : : encode_cookie(xdr, &args->cookie);
360 : 0 : encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
361 : 0 : encode_nlm_lock(xdr, lock);
362 : 0 : }
363 : :
364 : : /*
365 : : * struct nlm_lockargs {
366 : : * netobj cookie;
367 : : * bool block;
368 : : * bool exclusive;
369 : : * struct nlm_lock alock;
370 : : * bool reclaim;
371 : : * int state;
372 : : * };
373 : : */
374 : 0 : static void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
375 : : struct xdr_stream *xdr,
376 : : const void *data)
377 : : {
378 : : const struct nlm_args *args = data;
379 : 0 : const struct nlm_lock *lock = &args->lock;
380 : :
381 : : encode_cookie(xdr, &args->cookie);
382 : 0 : encode_bool(xdr, args->block);
383 : 0 : encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
384 : 0 : encode_nlm_lock(xdr, lock);
385 : 0 : encode_bool(xdr, args->reclaim);
386 : 0 : encode_int32(xdr, args->state);
387 : 0 : }
388 : :
389 : : /*
390 : : * struct nlm_cancargs {
391 : : * netobj cookie;
392 : : * bool block;
393 : : * bool exclusive;
394 : : * struct nlm_lock alock;
395 : : * };
396 : : */
397 : 0 : static void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
398 : : struct xdr_stream *xdr,
399 : : const void *data)
400 : : {
401 : : const struct nlm_args *args = data;
402 : 0 : const struct nlm_lock *lock = &args->lock;
403 : :
404 : : encode_cookie(xdr, &args->cookie);
405 : 0 : encode_bool(xdr, args->block);
406 : 0 : encode_bool(xdr, lock->fl.fl_type == F_WRLCK);
407 : 0 : encode_nlm_lock(xdr, lock);
408 : 0 : }
409 : :
410 : : /*
411 : : * struct nlm_unlockargs {
412 : : * netobj cookie;
413 : : * struct nlm_lock alock;
414 : : * };
415 : : */
416 : 0 : static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req,
417 : : struct xdr_stream *xdr,
418 : : const void *data)
419 : : {
420 : : const struct nlm_args *args = data;
421 : 0 : const struct nlm_lock *lock = &args->lock;
422 : :
423 : : encode_cookie(xdr, &args->cookie);
424 : 0 : encode_nlm_lock(xdr, lock);
425 : 0 : }
426 : :
427 : : /*
428 : : * struct nlm_res {
429 : : * netobj cookie;
430 : : * nlm_stat stat;
431 : : * };
432 : : */
433 : 0 : static void nlm_xdr_enc_res(struct rpc_rqst *req,
434 : : struct xdr_stream *xdr,
435 : : const void *data)
436 : : {
437 : : const struct nlm_res *result = data;
438 : :
439 : : encode_cookie(xdr, &result->cookie);
440 : 0 : encode_nlm_stat(xdr, result->status);
441 : 0 : }
442 : :
443 : : /*
444 : : * union nlm_testrply switch (nlm_stats stat) {
445 : : * case LCK_DENIED:
446 : : * struct nlm_holder holder;
447 : : * default:
448 : : * void;
449 : : * };
450 : : *
451 : : * struct nlm_testres {
452 : : * netobj cookie;
453 : : * nlm_testrply test_stat;
454 : : * };
455 : : */
456 : : static void encode_nlm_testrply(struct xdr_stream *xdr,
457 : : const struct nlm_res *result)
458 : : {
459 : 0 : if (result->status == nlm_lck_denied)
460 : 0 : encode_nlm_holder(xdr, result);
461 : : }
462 : :
463 : 0 : static void nlm_xdr_enc_testres(struct rpc_rqst *req,
464 : : struct xdr_stream *xdr,
465 : : const void *data)
466 : : {
467 : : const struct nlm_res *result = data;
468 : :
469 : : encode_cookie(xdr, &result->cookie);
470 : 0 : encode_nlm_stat(xdr, result->status);
471 : : encode_nlm_testrply(xdr, result);
472 : 0 : }
473 : :
474 : :
475 : : /*
476 : : * NLMv3 XDR decode functions
477 : : *
478 : : * NLMv3 result types are defined in Chapter 10 of The Open Group's
479 : : * "Protocols for Interworking: XNFS, Version 3W".
480 : : */
481 : :
482 : : /*
483 : : * union nlm_testrply switch (nlm_stats stat) {
484 : : * case LCK_DENIED:
485 : : * struct nlm_holder holder;
486 : : * default:
487 : : * void;
488 : : * };
489 : : *
490 : : * struct nlm_testres {
491 : : * netobj cookie;
492 : : * nlm_testrply test_stat;
493 : : * };
494 : : */
495 : 0 : static int decode_nlm_testrply(struct xdr_stream *xdr,
496 : : struct nlm_res *result)
497 : : {
498 : : int error;
499 : :
500 : 0 : error = decode_nlm_stat(xdr, &result->status);
501 : 0 : if (unlikely(error))
502 : : goto out;
503 : 0 : if (result->status == nlm_lck_denied)
504 : 0 : error = decode_nlm_holder(xdr, result);
505 : : out:
506 : 0 : return error;
507 : : }
508 : :
509 : 0 : static int nlm_xdr_dec_testres(struct rpc_rqst *req,
510 : : struct xdr_stream *xdr,
511 : : void *data)
512 : : {
513 : : struct nlm_res *result = data;
514 : : int error;
515 : :
516 : 0 : error = decode_cookie(xdr, &result->cookie);
517 : 0 : if (unlikely(error))
518 : : goto out;
519 : 0 : error = decode_nlm_testrply(xdr, result);
520 : : out:
521 : 0 : return error;
522 : : }
523 : :
524 : : /*
525 : : * struct nlm_res {
526 : : * netobj cookie;
527 : : * nlm_stat stat;
528 : : * };
529 : : */
530 : 0 : static int nlm_xdr_dec_res(struct rpc_rqst *req,
531 : : struct xdr_stream *xdr,
532 : : void *data)
533 : : {
534 : : struct nlm_res *result = data;
535 : : int error;
536 : :
537 : 0 : error = decode_cookie(xdr, &result->cookie);
538 : 0 : if (unlikely(error))
539 : : goto out;
540 : 0 : error = decode_nlm_stat(xdr, &result->status);
541 : : out:
542 : 0 : return error;
543 : : }
544 : :
545 : :
546 : : /*
547 : : * For NLM, a void procedure really returns nothing
548 : : */
549 : : #define nlm_xdr_dec_norep NULL
550 : :
551 : : #define PROC(proc, argtype, restype) \
552 : : [NLMPROC_##proc] = { \
553 : : .p_proc = NLMPROC_##proc, \
554 : : .p_encode = nlm_xdr_enc_##argtype, \
555 : : .p_decode = nlm_xdr_dec_##restype, \
556 : : .p_arglen = NLM_##argtype##_sz, \
557 : : .p_replen = NLM_##restype##_sz, \
558 : : .p_statidx = NLMPROC_##proc, \
559 : : .p_name = #proc, \
560 : : }
561 : :
562 : : static const struct rpc_procinfo nlm_procedures[] = {
563 : : PROC(TEST, testargs, testres),
564 : : PROC(LOCK, lockargs, res),
565 : : PROC(CANCEL, cancargs, res),
566 : : PROC(UNLOCK, unlockargs, res),
567 : : PROC(GRANTED, testargs, res),
568 : : PROC(TEST_MSG, testargs, norep),
569 : : PROC(LOCK_MSG, lockargs, norep),
570 : : PROC(CANCEL_MSG, cancargs, norep),
571 : : PROC(UNLOCK_MSG, unlockargs, norep),
572 : : PROC(GRANTED_MSG, testargs, norep),
573 : : PROC(TEST_RES, testres, norep),
574 : : PROC(LOCK_RES, res, norep),
575 : : PROC(CANCEL_RES, res, norep),
576 : : PROC(UNLOCK_RES, res, norep),
577 : : PROC(GRANTED_RES, res, norep),
578 : : };
579 : :
580 : : static unsigned int nlm_version1_counts[ARRAY_SIZE(nlm_procedures)];
581 : : static const struct rpc_version nlm_version1 = {
582 : : .number = 1,
583 : : .nrprocs = ARRAY_SIZE(nlm_procedures),
584 : : .procs = nlm_procedures,
585 : : .counts = nlm_version1_counts,
586 : : };
587 : :
588 : : static unsigned int nlm_version3_counts[ARRAY_SIZE(nlm_procedures)];
589 : : static const struct rpc_version nlm_version3 = {
590 : : .number = 3,
591 : : .nrprocs = ARRAY_SIZE(nlm_procedures),
592 : : .procs = nlm_procedures,
593 : : .counts = nlm_version3_counts,
594 : : };
595 : :
596 : : static const struct rpc_version *nlm_versions[] = {
597 : : [1] = &nlm_version1,
598 : : [3] = &nlm_version3,
599 : : #ifdef CONFIG_LOCKD_V4
600 : : [4] = &nlm_version4,
601 : : #endif
602 : : };
603 : :
604 : : static struct rpc_stat nlm_rpc_stats;
605 : :
606 : : const struct rpc_program nlm_program = {
607 : : .name = "lockd",
608 : : .number = NLM_PROGRAM,
609 : : .nrvers = ARRAY_SIZE(nlm_versions),
610 : : .version = nlm_versions,
611 : : .stats = &nlm_rpc_stats,
612 : : };
|