xref: /openbmc/linux/fs/lockd/xdr.c (revision 1fa6ac37)
1 /*
2  * linux/fs/lockd/xdr.c
3  *
4  * XDR support for lockd and the lock client.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8 
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/nfs.h>
12 
13 #include <linux/sunrpc/xdr.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/sunrpc/svc.h>
16 #include <linux/sunrpc/stats.h>
17 #include <linux/lockd/lockd.h>
18 
19 #define NLMDBG_FACILITY		NLMDBG_XDR
20 
21 
22 static inline loff_t
23 s32_to_loff_t(__s32 offset)
24 {
25 	return (loff_t)offset;
26 }
27 
28 static inline __s32
29 loff_t_to_s32(loff_t offset)
30 {
31 	__s32 res;
32 	if (offset >= NLM_OFFSET_MAX)
33 		res = NLM_OFFSET_MAX;
34 	else if (offset <= -NLM_OFFSET_MAX)
35 		res = -NLM_OFFSET_MAX;
36 	else
37 		res = offset;
38 	return res;
39 }
40 
41 /*
42  * XDR functions for basic NLM types
43  */
44 static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
45 {
46 	unsigned int	len;
47 
48 	len = ntohl(*p++);
49 
50 	if(len==0)
51 	{
52 		c->len=4;
53 		memset(c->data, 0, 4);	/* hockeypux brain damage */
54 	}
55 	else if(len<=NLM_MAXCOOKIELEN)
56 	{
57 		c->len=len;
58 		memcpy(c->data, p, len);
59 		p+=XDR_QUADLEN(len);
60 	}
61 	else
62 	{
63 		dprintk("lockd: bad cookie size %d (only cookies under "
64 			"%d bytes are supported.)\n",
65 				len, NLM_MAXCOOKIELEN);
66 		return NULL;
67 	}
68 	return p;
69 }
70 
71 static inline __be32 *
72 nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
73 {
74 	*p++ = htonl(c->len);
75 	memcpy(p, c->data, c->len);
76 	p+=XDR_QUADLEN(c->len);
77 	return p;
78 }
79 
80 static __be32 *
81 nlm_decode_fh(__be32 *p, struct nfs_fh *f)
82 {
83 	unsigned int	len;
84 
85 	if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
86 		dprintk("lockd: bad fhandle size %d (should be %d)\n",
87 			len, NFS2_FHSIZE);
88 		return NULL;
89 	}
90 	f->size = NFS2_FHSIZE;
91 	memset(f->data, 0, sizeof(f->data));
92 	memcpy(f->data, p, NFS2_FHSIZE);
93 	return p + XDR_QUADLEN(NFS2_FHSIZE);
94 }
95 
96 static inline __be32 *
97 nlm_encode_fh(__be32 *p, struct nfs_fh *f)
98 {
99 	*p++ = htonl(NFS2_FHSIZE);
100 	memcpy(p, f->data, NFS2_FHSIZE);
101 	return p + XDR_QUADLEN(NFS2_FHSIZE);
102 }
103 
104 /*
105  * Encode and decode owner handle
106  */
107 static inline __be32 *
108 nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
109 {
110 	return xdr_decode_netobj(p, oh);
111 }
112 
113 static inline __be32 *
114 nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
115 {
116 	return xdr_encode_netobj(p, oh);
117 }
118 
119 static __be32 *
120 nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
121 {
122 	struct file_lock	*fl = &lock->fl;
123 	s32			start, len, end;
124 
125 	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
126 					    &lock->len,
127 					    NLM_MAXSTRLEN))
128 	 || !(p = nlm_decode_fh(p, &lock->fh))
129 	 || !(p = nlm_decode_oh(p, &lock->oh)))
130 		return NULL;
131 	lock->svid  = ntohl(*p++);
132 
133 	locks_init_lock(fl);
134 	fl->fl_owner = current->files;
135 	fl->fl_pid   = (pid_t)lock->svid;
136 	fl->fl_flags = FL_POSIX;
137 	fl->fl_type  = F_RDLCK;		/* as good as anything else */
138 	start = ntohl(*p++);
139 	len = ntohl(*p++);
140 	end = start + len - 1;
141 
142 	fl->fl_start = s32_to_loff_t(start);
143 
144 	if (len == 0 || end < 0)
145 		fl->fl_end = OFFSET_MAX;
146 	else
147 		fl->fl_end = s32_to_loff_t(end);
148 	return p;
149 }
150 
151 /*
152  * Encode a lock as part of an NLM call
153  */
154 static __be32 *
155 nlm_encode_lock(__be32 *p, struct nlm_lock *lock)
156 {
157 	struct file_lock	*fl = &lock->fl;
158 	__s32			start, len;
159 
160 	if (!(p = xdr_encode_string(p, lock->caller))
161 	 || !(p = nlm_encode_fh(p, &lock->fh))
162 	 || !(p = nlm_encode_oh(p, &lock->oh)))
163 		return NULL;
164 
165 	if (fl->fl_start > NLM_OFFSET_MAX
166 	 || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
167 		return NULL;
168 
169 	start = loff_t_to_s32(fl->fl_start);
170 	if (fl->fl_end == OFFSET_MAX)
171 		len = 0;
172 	else
173 		len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
174 
175 	*p++ = htonl(lock->svid);
176 	*p++ = htonl(start);
177 	*p++ = htonl(len);
178 
179 	return p;
180 }
181 
182 /*
183  * Encode result of a TEST/TEST_MSG call
184  */
185 static __be32 *
186 nlm_encode_testres(__be32 *p, struct nlm_res *resp)
187 {
188 	s32		start, len;
189 
190 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
191 		return NULL;
192 	*p++ = resp->status;
193 
194 	if (resp->status == nlm_lck_denied) {
195 		struct file_lock	*fl = &resp->lock.fl;
196 
197 		*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
198 		*p++ = htonl(resp->lock.svid);
199 
200 		/* Encode owner handle. */
201 		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
202 			return NULL;
203 
204 		start = loff_t_to_s32(fl->fl_start);
205 		if (fl->fl_end == OFFSET_MAX)
206 			len = 0;
207 		else
208 			len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
209 
210 		*p++ = htonl(start);
211 		*p++ = htonl(len);
212 	}
213 
214 	return p;
215 }
216 
217 
218 /*
219  * First, the server side XDR functions
220  */
221 int
222 nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
223 {
224 	u32	exclusive;
225 
226 	if (!(p = nlm_decode_cookie(p, &argp->cookie)))
227 		return 0;
228 
229 	exclusive = ntohl(*p++);
230 	if (!(p = nlm_decode_lock(p, &argp->lock)))
231 		return 0;
232 	if (exclusive)
233 		argp->lock.fl.fl_type = F_WRLCK;
234 
235 	return xdr_argsize_check(rqstp, p);
236 }
237 
238 int
239 nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
240 {
241 	if (!(p = nlm_encode_testres(p, resp)))
242 		return 0;
243 	return xdr_ressize_check(rqstp, p);
244 }
245 
246 int
247 nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
248 {
249 	u32	exclusive;
250 
251 	if (!(p = nlm_decode_cookie(p, &argp->cookie)))
252 		return 0;
253 	argp->block  = ntohl(*p++);
254 	exclusive    = ntohl(*p++);
255 	if (!(p = nlm_decode_lock(p, &argp->lock)))
256 		return 0;
257 	if (exclusive)
258 		argp->lock.fl.fl_type = F_WRLCK;
259 	argp->reclaim = ntohl(*p++);
260 	argp->state   = ntohl(*p++);
261 	argp->monitor = 1;		/* monitor client by default */
262 
263 	return xdr_argsize_check(rqstp, p);
264 }
265 
266 int
267 nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
268 {
269 	u32	exclusive;
270 
271 	if (!(p = nlm_decode_cookie(p, &argp->cookie)))
272 		return 0;
273 	argp->block = ntohl(*p++);
274 	exclusive = ntohl(*p++);
275 	if (!(p = nlm_decode_lock(p, &argp->lock)))
276 		return 0;
277 	if (exclusive)
278 		argp->lock.fl.fl_type = F_WRLCK;
279 	return xdr_argsize_check(rqstp, p);
280 }
281 
282 int
283 nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
284 {
285 	if (!(p = nlm_decode_cookie(p, &argp->cookie))
286 	 || !(p = nlm_decode_lock(p, &argp->lock)))
287 		return 0;
288 	argp->lock.fl.fl_type = F_UNLCK;
289 	return xdr_argsize_check(rqstp, p);
290 }
291 
292 int
293 nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
294 {
295 	struct nlm_lock	*lock = &argp->lock;
296 
297 	memset(lock, 0, sizeof(*lock));
298 	locks_init_lock(&lock->fl);
299 	lock->svid = ~(u32) 0;
300 	lock->fl.fl_pid = (pid_t)lock->svid;
301 
302 	if (!(p = nlm_decode_cookie(p, &argp->cookie))
303 	 || !(p = xdr_decode_string_inplace(p, &lock->caller,
304 					    &lock->len, NLM_MAXSTRLEN))
305 	 || !(p = nlm_decode_fh(p, &lock->fh))
306 	 || !(p = nlm_decode_oh(p, &lock->oh)))
307 		return 0;
308 	argp->fsm_mode = ntohl(*p++);
309 	argp->fsm_access = ntohl(*p++);
310 	return xdr_argsize_check(rqstp, p);
311 }
312 
313 int
314 nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
315 {
316 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
317 		return 0;
318 	*p++ = resp->status;
319 	*p++ = xdr_zero;		/* sequence argument */
320 	return xdr_ressize_check(rqstp, p);
321 }
322 
323 int
324 nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
325 {
326 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
327 		return 0;
328 	*p++ = resp->status;
329 	return xdr_ressize_check(rqstp, p);
330 }
331 
332 int
333 nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
334 {
335 	struct nlm_lock	*lock = &argp->lock;
336 
337 	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
338 					    &lock->len, NLM_MAXSTRLEN)))
339 		return 0;
340 	argp->state = ntohl(*p++);
341 	return xdr_argsize_check(rqstp, p);
342 }
343 
344 int
345 nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
346 {
347 	if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
348 		return 0;
349 	argp->state = ntohl(*p++);
350 	memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
351 	p += XDR_QUADLEN(SM_PRIV_SIZE);
352 	return xdr_argsize_check(rqstp, p);
353 }
354 
355 int
356 nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
357 {
358 	if (!(p = nlm_decode_cookie(p, &resp->cookie)))
359 		return 0;
360 	resp->status = *p++;
361 	return xdr_argsize_check(rqstp, p);
362 }
363 
364 int
365 nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
366 {
367 	return xdr_argsize_check(rqstp, p);
368 }
369 
370 int
371 nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
372 {
373 	return xdr_ressize_check(rqstp, p);
374 }
375 
376 /*
377  * Now, the client side XDR functions
378  */
379 #ifdef NLMCLNT_SUPPORT_SHARES
380 static int
381 nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
382 {
383 	return 0;
384 }
385 #endif
386 
387 static int
388 nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
389 {
390 	struct nlm_lock	*lock = &argp->lock;
391 
392 	if (!(p = nlm_encode_cookie(p, &argp->cookie)))
393 		return -EIO;
394 	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
395 	if (!(p = nlm_encode_lock(p, lock)))
396 		return -EIO;
397 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
398 	return 0;
399 }
400 
401 static int
402 nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
403 {
404 	if (!(p = nlm_decode_cookie(p, &resp->cookie)))
405 		return -EIO;
406 	resp->status = *p++;
407 	if (resp->status == nlm_lck_denied) {
408 		struct file_lock	*fl = &resp->lock.fl;
409 		u32			excl;
410 		s32			start, len, end;
411 
412 		memset(&resp->lock, 0, sizeof(resp->lock));
413 		locks_init_lock(fl);
414 		excl = ntohl(*p++);
415 		resp->lock.svid = ntohl(*p++);
416 		fl->fl_pid = (pid_t)resp->lock.svid;
417 		if (!(p = nlm_decode_oh(p, &resp->lock.oh)))
418 			return -EIO;
419 
420 		fl->fl_flags = FL_POSIX;
421 		fl->fl_type  = excl? F_WRLCK : F_RDLCK;
422 		start = ntohl(*p++);
423 		len = ntohl(*p++);
424 		end = start + len - 1;
425 
426 		fl->fl_start = s32_to_loff_t(start);
427 		if (len == 0 || end < 0)
428 			fl->fl_end = OFFSET_MAX;
429 		else
430 			fl->fl_end = s32_to_loff_t(end);
431 	}
432 	return 0;
433 }
434 
435 
436 static int
437 nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
438 {
439 	struct nlm_lock	*lock = &argp->lock;
440 
441 	if (!(p = nlm_encode_cookie(p, &argp->cookie)))
442 		return -EIO;
443 	*p++ = argp->block? xdr_one : xdr_zero;
444 	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
445 	if (!(p = nlm_encode_lock(p, lock)))
446 		return -EIO;
447 	*p++ = argp->reclaim? xdr_one : xdr_zero;
448 	*p++ = htonl(argp->state);
449 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
450 	return 0;
451 }
452 
453 static int
454 nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
455 {
456 	struct nlm_lock	*lock = &argp->lock;
457 
458 	if (!(p = nlm_encode_cookie(p, &argp->cookie)))
459 		return -EIO;
460 	*p++ = argp->block? xdr_one : xdr_zero;
461 	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
462 	if (!(p = nlm_encode_lock(p, lock)))
463 		return -EIO;
464 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
465 	return 0;
466 }
467 
468 static int
469 nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
470 {
471 	struct nlm_lock	*lock = &argp->lock;
472 
473 	if (!(p = nlm_encode_cookie(p, &argp->cookie)))
474 		return -EIO;
475 	if (!(p = nlm_encode_lock(p, lock)))
476 		return -EIO;
477 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
478 	return 0;
479 }
480 
481 static int
482 nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
483 {
484 	if (!(p = nlm_encode_cookie(p, &resp->cookie)))
485 		return -EIO;
486 	*p++ = resp->status;
487 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
488 	return 0;
489 }
490 
491 static int
492 nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
493 {
494 	if (!(p = nlm_encode_testres(p, resp)))
495 		return -EIO;
496 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
497 	return 0;
498 }
499 
500 static int
501 nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
502 {
503 	if (!(p = nlm_decode_cookie(p, &resp->cookie)))
504 		return -EIO;
505 	resp->status = *p++;
506 	return 0;
507 }
508 
509 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
510 #  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
511 #endif
512 
513 /*
514  * Buffer requirements for NLM
515  */
516 #define NLM_void_sz		0
517 #define NLM_cookie_sz		1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
518 #define NLM_caller_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
519 #define NLM_owner_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
520 #define NLM_fhandle_sz		1+XDR_QUADLEN(NFS2_FHSIZE)
521 #define NLM_lock_sz		3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz
522 #define NLM_holder_sz		4+NLM_owner_sz
523 
524 #define NLM_testargs_sz		NLM_cookie_sz+1+NLM_lock_sz
525 #define NLM_lockargs_sz		NLM_cookie_sz+4+NLM_lock_sz
526 #define NLM_cancargs_sz		NLM_cookie_sz+2+NLM_lock_sz
527 #define NLM_unlockargs_sz	NLM_cookie_sz+NLM_lock_sz
528 
529 #define NLM_testres_sz		NLM_cookie_sz+1+NLM_holder_sz
530 #define NLM_res_sz		NLM_cookie_sz+1
531 #define NLM_norep_sz		0
532 
533 /*
534  * For NLM, a void procedure really returns nothing
535  */
536 #define nlmclt_decode_norep	NULL
537 
538 #define PROC(proc, argtype, restype)	\
539 [NLMPROC_##proc] = {							\
540 	.p_proc      = NLMPROC_##proc,					\
541 	.p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,		\
542 	.p_decode    = (kxdrproc_t) nlmclt_decode_##restype,		\
543 	.p_arglen    = NLM_##argtype##_sz,				\
544 	.p_replen    = NLM_##restype##_sz,				\
545 	.p_statidx   = NLMPROC_##proc,					\
546 	.p_name      = #proc,						\
547 	}
548 
549 static struct rpc_procinfo	nlm_procedures[] = {
550     PROC(TEST,		testargs,	testres),
551     PROC(LOCK,		lockargs,	res),
552     PROC(CANCEL,	cancargs,	res),
553     PROC(UNLOCK,	unlockargs,	res),
554     PROC(GRANTED,	testargs,	res),
555     PROC(TEST_MSG,	testargs,	norep),
556     PROC(LOCK_MSG,	lockargs,	norep),
557     PROC(CANCEL_MSG,	cancargs,	norep),
558     PROC(UNLOCK_MSG,	unlockargs,	norep),
559     PROC(GRANTED_MSG,	testargs,	norep),
560     PROC(TEST_RES,	testres,	norep),
561     PROC(LOCK_RES,	res,		norep),
562     PROC(CANCEL_RES,	res,		norep),
563     PROC(UNLOCK_RES,	res,		norep),
564     PROC(GRANTED_RES,	res,		norep),
565 #ifdef NLMCLNT_SUPPORT_SHARES
566     PROC(SHARE,		shareargs,	shareres),
567     PROC(UNSHARE,	shareargs,	shareres),
568     PROC(NM_LOCK,	lockargs,	res),
569     PROC(FREE_ALL,	notify,		void),
570 #endif
571 };
572 
573 static struct rpc_version	nlm_version1 = {
574 		.number		= 1,
575 		.nrprocs	= 16,
576 		.procs		= nlm_procedures,
577 };
578 
579 static struct rpc_version	nlm_version3 = {
580 		.number		= 3,
581 		.nrprocs	= 24,
582 		.procs		= nlm_procedures,
583 };
584 
585 static struct rpc_version *	nlm_versions[] = {
586 	[1] = &nlm_version1,
587 	[3] = &nlm_version3,
588 #ifdef 	CONFIG_LOCKD_V4
589 	[4] = &nlm_version4,
590 #endif
591 };
592 
593 static struct rpc_stat		nlm_stats;
594 
595 struct rpc_program		nlm_program = {
596 		.name		= "lockd",
597 		.number		= NLM_PROGRAM,
598 		.nrvers		= ARRAY_SIZE(nlm_versions),
599 		.version	= nlm_versions,
600 		.stats		= &nlm_stats,
601 };
602 
603 #ifdef RPC_DEBUG
604 const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
605 {
606 	/*
607 	 * We can get away with a static buffer because we're only
608 	 * called with BKL held.
609 	 */
610 	static char buf[2*NLM_MAXCOOKIELEN+1];
611 	unsigned int i, len = sizeof(buf);
612 	char *p = buf;
613 
614 	len--;	/* allow for trailing \0 */
615 	if (len < 3)
616 		return "???";
617 	for (i = 0 ; i < cookie->len ; i++) {
618 		if (len < 2) {
619 			strcpy(p-3, "...");
620 			break;
621 		}
622 		sprintf(p, "%02x", cookie->data[i]);
623 		p += 2;
624 		len -= 2;
625 	}
626 	*p = '\0';
627 
628 	return buf;
629 }
630 #endif
631