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