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