xref: /openbmc/linux/fs/lockd/xdr4.c (revision fd589a8f)
1 /*
2  * linux/fs/lockd/xdr4.c
3  *
4  * XDR support for lockd and the lock client.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
8  */
9 
10 #include <linux/types.h>
11 #include <linux/sched.h>
12 #include <linux/utsname.h>
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>
20 
21 #define NLMDBG_FACILITY		NLMDBG_XDR
22 
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 
43 /*
44  * XDR functions for basic NLM types
45  */
46 static __be32 *
47 nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
48 {
49 	unsigned int	len;
50 
51 	len = ntohl(*p++);
52 
53 	if(len==0)
54 	{
55 		c->len=4;
56 		memset(c->data, 0, 4);	/* hockeypux brain damage */
57 	}
58 	else if(len<=NLM_MAXCOOKIELEN)
59 	{
60 		c->len=len;
61 		memcpy(c->data, p, len);
62 		p+=XDR_QUADLEN(len);
63 	}
64 	else
65 	{
66 		dprintk("lockd: bad cookie size %d (only cookies under "
67 			"%d bytes are supported.)\n",
68 				len, NLM_MAXCOOKIELEN);
69 		return NULL;
70 	}
71 	return p;
72 }
73 
74 static __be32 *
75 nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
76 {
77 	*p++ = htonl(c->len);
78 	memcpy(p, c->data, c->len);
79 	p+=XDR_QUADLEN(c->len);
80 	return p;
81 }
82 
83 static __be32 *
84 nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
85 {
86 	memset(f->data, 0, sizeof(f->data));
87 	f->size = ntohl(*p++);
88 	if (f->size > NFS_MAXFHSIZE) {
89 		dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
90 			f->size, NFS_MAXFHSIZE);
91 		return NULL;
92 	}
93       	memcpy(f->data, p, f->size);
94 	return p + XDR_QUADLEN(f->size);
95 }
96 
97 static __be32 *
98 nlm4_encode_fh(__be32 *p, struct nfs_fh *f)
99 {
100 	*p++ = htonl(f->size);
101 	if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
102 	memcpy(p, f->data, f->size);
103 	return p + XDR_QUADLEN(f->size);
104 }
105 
106 /*
107  * Encode and decode owner handle
108  */
109 static __be32 *
110 nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
111 {
112 	return xdr_decode_netobj(p, oh);
113 }
114 
115 static __be32 *
116 nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh)
117 {
118 	return xdr_encode_netobj(p, oh);
119 }
120 
121 static __be32 *
122 nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
123 {
124 	struct file_lock	*fl = &lock->fl;
125 	__u64			len, start;
126 	__s64			end;
127 
128 	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
129 					    &lock->len, NLM_MAXSTRLEN))
130 	 || !(p = nlm4_decode_fh(p, &lock->fh))
131 	 || !(p = nlm4_decode_oh(p, &lock->oh)))
132 		return NULL;
133 	lock->svid  = ntohl(*p++);
134 
135 	locks_init_lock(fl);
136 	fl->fl_owner = current->files;
137 	fl->fl_pid   = (pid_t)lock->svid;
138 	fl->fl_flags = FL_POSIX;
139 	fl->fl_type  = F_RDLCK;		/* as good as anything else */
140 	p = xdr_decode_hyper(p, &start);
141 	p = xdr_decode_hyper(p, &len);
142 	end = start + len - 1;
143 
144 	fl->fl_start = s64_to_loff_t(start);
145 
146 	if (len == 0 || end < 0)
147 		fl->fl_end = OFFSET_MAX;
148 	else
149 		fl->fl_end = s64_to_loff_t(end);
150 	return p;
151 }
152 
153 /*
154  * Encode a lock as part of an NLM call
155  */
156 static __be32 *
157 nlm4_encode_lock(__be32 *p, struct nlm_lock *lock)
158 {
159 	struct file_lock	*fl = &lock->fl;
160 	__s64			start, len;
161 
162 	if (!(p = xdr_encode_string(p, lock->caller))
163 	 || !(p = nlm4_encode_fh(p, &lock->fh))
164 	 || !(p = nlm4_encode_oh(p, &lock->oh)))
165 		return NULL;
166 
167 	if (fl->fl_start > NLM4_OFFSET_MAX
168 	 || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
169 		return NULL;
170 
171 	*p++ = htonl(lock->svid);
172 
173 	start = loff_t_to_s64(fl->fl_start);
174 	if (fl->fl_end == OFFSET_MAX)
175 		len = 0;
176 	else
177 		len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
178 
179 	p = xdr_encode_hyper(p, start);
180 	p = xdr_encode_hyper(p, len);
181 
182 	return p;
183 }
184 
185 /*
186  * Encode result of a TEST/TEST_MSG call
187  */
188 static __be32 *
189 nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
190 {
191 	s64		start, len;
192 
193 	dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
194 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
195 		return NULL;
196 	*p++ = resp->status;
197 
198 	if (resp->status == nlm_lck_denied) {
199 		struct file_lock	*fl = &resp->lock.fl;
200 
201 		*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
202 		*p++ = htonl(resp->lock.svid);
203 
204 		/* Encode owner handle. */
205 		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
206 			return NULL;
207 
208 		start = loff_t_to_s64(fl->fl_start);
209 		if (fl->fl_end == OFFSET_MAX)
210 			len = 0;
211 		else
212 			len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
213 
214 		p = xdr_encode_hyper(p, start);
215 		p = xdr_encode_hyper(p, len);
216 		dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n",
217 			resp->status, (int)resp->lock.svid, fl->fl_type,
218 			(long long)fl->fl_start,  (long long)fl->fl_end);
219 	}
220 
221 	dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
222 	return p;
223 }
224 
225 
226 /*
227  * First, the server side XDR functions
228  */
229 int
230 nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
231 {
232 	u32	exclusive;
233 
234 	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
235 		return 0;
236 
237 	exclusive = ntohl(*p++);
238 	if (!(p = nlm4_decode_lock(p, &argp->lock)))
239 		return 0;
240 	if (exclusive)
241 		argp->lock.fl.fl_type = F_WRLCK;
242 
243 	return xdr_argsize_check(rqstp, p);
244 }
245 
246 int
247 nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
248 {
249 	if (!(p = nlm4_encode_testres(p, resp)))
250 		return 0;
251 	return xdr_ressize_check(rqstp, p);
252 }
253 
254 int
255 nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
256 {
257 	u32	exclusive;
258 
259 	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
260 		return 0;
261 	argp->block  = ntohl(*p++);
262 	exclusive    = ntohl(*p++);
263 	if (!(p = nlm4_decode_lock(p, &argp->lock)))
264 		return 0;
265 	if (exclusive)
266 		argp->lock.fl.fl_type = F_WRLCK;
267 	argp->reclaim = ntohl(*p++);
268 	argp->state   = ntohl(*p++);
269 	argp->monitor = 1;		/* monitor client by default */
270 
271 	return xdr_argsize_check(rqstp, p);
272 }
273 
274 int
275 nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
276 {
277 	u32	exclusive;
278 
279 	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
280 		return 0;
281 	argp->block = ntohl(*p++);
282 	exclusive = ntohl(*p++);
283 	if (!(p = nlm4_decode_lock(p, &argp->lock)))
284 		return 0;
285 	if (exclusive)
286 		argp->lock.fl.fl_type = F_WRLCK;
287 	return xdr_argsize_check(rqstp, p);
288 }
289 
290 int
291 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
292 {
293 	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
294 	 || !(p = nlm4_decode_lock(p, &argp->lock)))
295 		return 0;
296 	argp->lock.fl.fl_type = F_UNLCK;
297 	return xdr_argsize_check(rqstp, p);
298 }
299 
300 int
301 nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
302 {
303 	struct nlm_lock	*lock = &argp->lock;
304 
305 	memset(lock, 0, sizeof(*lock));
306 	locks_init_lock(&lock->fl);
307 	lock->svid = ~(u32) 0;
308 	lock->fl.fl_pid = (pid_t)lock->svid;
309 
310 	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
311 	 || !(p = xdr_decode_string_inplace(p, &lock->caller,
312 					    &lock->len, NLM_MAXSTRLEN))
313 	 || !(p = nlm4_decode_fh(p, &lock->fh))
314 	 || !(p = nlm4_decode_oh(p, &lock->oh)))
315 		return 0;
316 	argp->fsm_mode = ntohl(*p++);
317 	argp->fsm_access = ntohl(*p++);
318 	return xdr_argsize_check(rqstp, p);
319 }
320 
321 int
322 nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
323 {
324 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
325 		return 0;
326 	*p++ = resp->status;
327 	*p++ = xdr_zero;		/* sequence argument */
328 	return xdr_ressize_check(rqstp, p);
329 }
330 
331 int
332 nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
333 {
334 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
335 		return 0;
336 	*p++ = resp->status;
337 	return xdr_ressize_check(rqstp, p);
338 }
339 
340 int
341 nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
342 {
343 	struct nlm_lock	*lock = &argp->lock;
344 
345 	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
346 					    &lock->len, NLM_MAXSTRLEN)))
347 		return 0;
348 	argp->state = ntohl(*p++);
349 	return xdr_argsize_check(rqstp, p);
350 }
351 
352 int
353 nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
354 {
355 	if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
356 		return 0;
357 	argp->state = ntohl(*p++);
358 	memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
359 	p += XDR_QUADLEN(SM_PRIV_SIZE);
360 	return xdr_argsize_check(rqstp, p);
361 }
362 
363 int
364 nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
365 {
366 	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
367 		return 0;
368 	resp->status = *p++;
369 	return xdr_argsize_check(rqstp, p);
370 }
371 
372 int
373 nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
374 {
375 	return xdr_argsize_check(rqstp, p);
376 }
377 
378 int
379 nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
380 {
381 	return xdr_ressize_check(rqstp, p);
382 }
383 
384 /*
385  * Now, the client side XDR functions
386  */
387 #ifdef NLMCLNT_SUPPORT_SHARES
388 static int
389 nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr)
390 {
391 	return 0;
392 }
393 #endif
394 
395 static int
396 nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
397 {
398 	struct nlm_lock	*lock = &argp->lock;
399 
400 	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
401 		return -EIO;
402 	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
403 	if (!(p = nlm4_encode_lock(p, lock)))
404 		return -EIO;
405 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
406 	return 0;
407 }
408 
409 static int
410 nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
411 {
412 	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
413 		return -EIO;
414 	resp->status = *p++;
415 	if (resp->status == nlm_lck_denied) {
416 		struct file_lock	*fl = &resp->lock.fl;
417 		u32			excl;
418 		__u64			start, len;
419 		__s64			end;
420 
421 		memset(&resp->lock, 0, sizeof(resp->lock));
422 		locks_init_lock(fl);
423 		excl = ntohl(*p++);
424 		resp->lock.svid = ntohl(*p++);
425 		fl->fl_pid = (pid_t)resp->lock.svid;
426 		if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
427 			return -EIO;
428 
429 		fl->fl_flags = FL_POSIX;
430 		fl->fl_type  = excl? F_WRLCK : F_RDLCK;
431 		p = xdr_decode_hyper(p, &start);
432 		p = xdr_decode_hyper(p, &len);
433 		end = start + len - 1;
434 
435 		fl->fl_start = s64_to_loff_t(start);
436 		if (len == 0 || end < 0)
437 			fl->fl_end = OFFSET_MAX;
438 		else
439 			fl->fl_end = s64_to_loff_t(end);
440 	}
441 	return 0;
442 }
443 
444 
445 static int
446 nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
447 {
448 	struct nlm_lock	*lock = &argp->lock;
449 
450 	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
451 		return -EIO;
452 	*p++ = argp->block? xdr_one : xdr_zero;
453 	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
454 	if (!(p = nlm4_encode_lock(p, lock)))
455 		return -EIO;
456 	*p++ = argp->reclaim? xdr_one : xdr_zero;
457 	*p++ = htonl(argp->state);
458 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
459 	return 0;
460 }
461 
462 static int
463 nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
464 {
465 	struct nlm_lock	*lock = &argp->lock;
466 
467 	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
468 		return -EIO;
469 	*p++ = argp->block? xdr_one : xdr_zero;
470 	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
471 	if (!(p = nlm4_encode_lock(p, lock)))
472 		return -EIO;
473 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
474 	return 0;
475 }
476 
477 static int
478 nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
479 {
480 	struct nlm_lock	*lock = &argp->lock;
481 
482 	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
483 		return -EIO;
484 	if (!(p = nlm4_encode_lock(p, lock)))
485 		return -EIO;
486 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
487 	return 0;
488 }
489 
490 static int
491 nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
492 {
493 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
494 		return -EIO;
495 	*p++ = resp->status;
496 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
497 	return 0;
498 }
499 
500 static int
501 nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
502 {
503 	if (!(p = nlm4_encode_testres(p, resp)))
504 		return -EIO;
505 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
506 	return 0;
507 }
508 
509 static int
510 nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
511 {
512 	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
513 		return -EIO;
514 	resp->status = *p++;
515 	return 0;
516 }
517 
518 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
519 #  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
520 #endif
521 
522 #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN)
523 #  error "NLM host name cannot be larger than NLM's maximum string length!"
524 #endif
525 
526 /*
527  * Buffer requirements for NLM
528  */
529 #define NLM4_void_sz		0
530 #define NLM4_cookie_sz		1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
531 #define NLM4_caller_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
532 #define NLM4_owner_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
533 #define NLM4_fhandle_sz		1+XDR_QUADLEN(NFS3_FHSIZE)
534 #define NLM4_lock_sz		5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz
535 #define NLM4_holder_sz		6+NLM4_owner_sz
536 
537 #define NLM4_testargs_sz	NLM4_cookie_sz+1+NLM4_lock_sz
538 #define NLM4_lockargs_sz	NLM4_cookie_sz+4+NLM4_lock_sz
539 #define NLM4_cancargs_sz	NLM4_cookie_sz+2+NLM4_lock_sz
540 #define NLM4_unlockargs_sz	NLM4_cookie_sz+NLM4_lock_sz
541 
542 #define NLM4_testres_sz		NLM4_cookie_sz+1+NLM4_holder_sz
543 #define NLM4_res_sz		NLM4_cookie_sz+1
544 #define NLM4_norep_sz		0
545 
546 /*
547  * For NLM, a void procedure really returns nothing
548  */
549 #define nlm4clt_decode_norep	NULL
550 
551 #define PROC(proc, argtype, restype)					\
552 [NLMPROC_##proc] = {							\
553 	.p_proc      = NLMPROC_##proc,					\
554 	.p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,		\
555 	.p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,		\
556 	.p_arglen    = NLM4_##argtype##_sz,				\
557 	.p_replen    = NLM4_##restype##_sz,				\
558 	.p_statidx   = NLMPROC_##proc,					\
559 	.p_name      = #proc,						\
560 	}
561 
562 static struct rpc_procinfo	nlm4_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 #ifdef NLMCLNT_SUPPORT_SHARES
579     PROC(SHARE,		shareargs,	shareres),
580     PROC(UNSHARE,	shareargs,	shareres),
581     PROC(NM_LOCK,	lockargs,	res),
582     PROC(FREE_ALL,	notify,		void),
583 #endif
584 };
585 
586 struct rpc_version	nlm_version4 = {
587 	.number		= 4,
588 	.nrprocs	= 24,
589 	.procs		= nlm4_procedures,
590 };
591