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