]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/nfs4client/nfs4_subs.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / nfs4client / nfs4_subs.c
1 /* $FreeBSD$ */
2 /* $Id: nfs4_subs.c,v 1.52 2003/11/05 14:58:59 rees Exp $ */
3
4 /*-
5  * copyright (c) 2003
6  * the regents of the university of michigan
7  * all rights reserved
8  * 
9  * permission is granted to use, copy, create derivative works and redistribute
10  * this software and such derivative works for any purpose, so long as the name
11  * of the university of michigan is not used in any advertising or publicity
12  * pertaining to the use or distribution of this software without specific,
13  * written prior authorization.  if the above copyright notice or any other
14  * identification of the university of michigan is included in any copy of any
15  * portion of this software, then the disclaimer below must also be included.
16  * 
17  * this software is provided as is, without representation from the university
18  * of michigan as to its fitness for any purpose, and without warranty by the
19  * university of michigan of any kind, either express or implied, including
20  * without limitation the implied warranties of merchantability and fitness for
21  * a particular purpose. the regents of the university of michigan shall not be
22  * liable for any damages, including special, indirect, incidental, or
23  * consequential damages, with respect to any claim arising out of or in
24  * connection with the use of the software, even if it has been or is hereafter
25  * advised of the possibility of such damages.
26  */
27
28 #include <sys/cdefs.h>
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bio.h>
34 #include <sys/buf.h>
35 #include <sys/proc.h>
36 #include <sys/mount.h>
37 #include <sys/vnode.h>
38 #include <sys/namei.h>
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/malloc.h>
43 #include <sys/sysent.h>
44 #include <sys/syscall.h>
45 #include <sys/sysproto.h>
46 #include <sys/fcntl.h>
47
48 #include <machine/stdarg.h>
49
50 #include <vm/vm.h>
51 #include <vm/vm_object.h>
52 #include <vm/vm_extern.h>
53 #include <vm/uma.h>
54
55 #include <rpc/rpcclnt.h>
56
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfsproto.h>
59 #include <nfsclient/nfs.h>
60 #include <nfs4client/nfs4.h>
61 #include <nfsclient/nfsnode.h>
62 #include <nfsclient/nfsmount.h>
63 #include <nfs/xdr_subs.h>
64 #include <nfsclient/nfsm_subs.h>
65
66 #include <nfs4client/nfs4_dev.h>
67 #include <nfs4client/nfs4_idmap.h>
68 #include <nfs4client/nfs4m_subs.h>
69
70 #include <netinet/in.h>
71
72 #define NFSM_DISSECT(s) do {                                                    \
73         tl = nfsm_dissect_xx((s), md, dpos);                                    \
74         if (tl == NULL) {                                                       \
75                 printf("NFSM_DISSECT error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__);  \
76                 return (EBADRPC);                                               \
77         }                                                                       \
78 } while (0)
79
80 #define NFSM_ADV(s) do {                                                \
81         t1 = nfsm_adv_xx((s), md, dpos);                                \
82         if (t1 != 0) {                                                  \
83                 printf("NFSM_ADV error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__);      \
84                 return (EBADRPC);                                       \
85         }                                                               \
86 } while (0)
87
88 #define NFSM_MTOTIME(t) do {                            \
89         NFSM_DISSECT(3 * NFSX_UNSIGNED);                \
90         (t).tv_sec = fxdr_hyper(tl);                    \
91         tl += 2;                                        \
92         (t).tv_nsec = fxdr_unsigned(long, *tl++);       \
93 } while (0)
94
95 static uint32_t __fsinfo_bm[2], __fsattr_bm[2], __getattr_bm[2], __readdir_bm[2];
96
97 nfsv4bitmap nfsv4_fsinfobm = { 2, __fsinfo_bm };
98 nfsv4bitmap nfsv4_fsattrbm = { 2, __fsattr_bm };
99 nfsv4bitmap nfsv4_getattrbm = { 2, __getattr_bm };
100 nfsv4bitmap nfsv4_readdirbm = { 2, __readdir_bm };
101
102 /* Helper routines */
103 int nfsm_v4build_attrs_xx(struct vattr *, struct mbuf **, caddr_t *);
104 int nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *,  struct mbuf **, caddr_t *);
105
106 void
107 nfsm_v4init(void)
108 {
109
110         /* Set up bitmasks */
111         FA4_SET(FA4_FSID, __fsinfo_bm);
112         FA4_SET(FA4_MAXREAD, __fsinfo_bm);
113         FA4_SET(FA4_MAXWRITE, __fsinfo_bm);
114         FA4_SET(FA4_LEASE_TIME, __fsinfo_bm);
115
116         FA4_SET(FA4_FSID, __fsattr_bm);
117         FA4_SET(FA4_FILES_FREE, __fsattr_bm);
118         FA4_SET(FA4_FILES_TOTAL, __fsattr_bm);
119         FA4_SET(FA4_SPACE_AVAIL, __fsattr_bm);
120         FA4_SET(FA4_SPACE_FREE, __fsattr_bm);
121         FA4_SET(FA4_SPACE_TOTAL, __fsattr_bm);
122
123         FA4_SET(FA4_TYPE, __getattr_bm);
124         FA4_SET(FA4_FSID, __getattr_bm);
125         FA4_SET(FA4_SIZE, __getattr_bm);
126         FA4_SET(FA4_MODE, __getattr_bm);
127         FA4_SET(FA4_RAWDEV, __getattr_bm);
128         FA4_SET(FA4_NUMLINKS, __getattr_bm);
129         FA4_SET(FA4_OWNER, __getattr_bm);
130         FA4_SET(FA4_OWNER_GROUP, __getattr_bm);
131         FA4_SET(FA4_FILEID, __getattr_bm);
132         FA4_SET(FA4_TIME_ACCESS, __getattr_bm);
133         FA4_SET(FA4_TIME_CREATE, __getattr_bm);
134         FA4_SET(FA4_TIME_METADATA, __getattr_bm);
135         FA4_SET(FA4_TIME_MODIFY, __getattr_bm);
136
137         FA4_SET(FA4_TYPE, __readdir_bm);
138         FA4_SET(FA4_FSID, __readdir_bm);
139         FA4_SET(FA4_FILEID, __readdir_bm);
140         FA4_SET(FA4_RDATTR_ERROR, __readdir_bm);
141 }
142
143 /*
144  * Util
145  */
146
147 uint32_t
148 nfs_v4fileid4_to_fileid(uint64_t fid)
149 {
150         return ((uint32_t)((fid >> 32) | fid));
151 }
152
153 void
154 nfs_v4initcompound(struct nfs4_compound *cp)
155 {
156         bzero(cp, sizeof(*cp));
157 }
158
159 /*
160  * Build/dissect XDR buffer with a format string.
161  *
162  *    u - unsigned
163  *    h - hyper
164  *    s - stringlength, string
165  *    k - skip length (bytes)
166  *    a - arraylength, componentlenght, array
167  *    o - opaque fix length
168  *    O - opaque var length in bytes
169  */
170
171 void
172 nfsm_buildf_xx(struct mbuf **mb, caddr_t *bpos, char *fmt, ...)
173 {
174         uint32_t *tl, t1, len, uval;
175         uint64_t hval;
176         va_list args;
177         char *p, *which;
178
179         va_start(args, fmt);
180         for (which = fmt; *which != '\0'; which++)
181                 switch (*which) {
182                 case 'u':       /* Unsigned */
183                         tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
184                         uval = va_arg(args, uint32_t);
185                         *tl++ = txdr_unsigned(uval);
186                         break;
187                 case 'h':       /* Hyper */
188                         tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
189                         hval = va_arg(args, uint64_t);
190                         txdr_hyper(hval, tl);
191                         break;
192                 case 'o':       /* Fixed-length opaque */
193                         len = va_arg(args, uint32_t);
194                         p = va_arg(args, char *);
195                         tl = nfsm_build_xx(nfsm_rndup(len), mb, bpos);
196                         bcopy(p, tl, len);
197                         break;
198                 case 'O':       /* Variable-length opaque */
199                 case 's':       /* String */
200                         len = va_arg(args, uint32_t);
201                         p = va_arg(args, char *);
202                         t1 = nfsm_strtom_xx(p, len, len, mb, bpos);
203                         break;
204                 case 'k':       /* Skip */
205                         len = va_arg(args, uint32_t);
206                         nfsm_build_xx(nfsm_rndup(len), mb, bpos);
207                         break;
208                 default:
209                         panic("Invalid buildf string %s[%c]", fmt, *which);
210                         break;
211                 }
212         va_end(args);
213 }
214
215 int
216 nfsm_dissectf_xx(struct mbuf **md, caddr_t *dpos, char *fmt, ...)
217 {
218         uint32_t *tl, t1, len, *uval;
219         uint64_t *hval;
220         va_list args;
221         char *p, *which;
222
223         va_start(args, fmt);
224         for (which = fmt; *which != '\0'; which++)
225                 switch (*which) {
226                 case 'u':       /* Unsigned */
227                         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
228                         if (tl == NULL)
229                                 return (EBADRPC);
230                         uval = va_arg(args, uint32_t *);
231                         *uval = fxdr_unsigned(uint32_t, *tl++);
232                         break;
233                 case 'h':       /* Hyper */
234                         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
235                         if (tl == NULL)
236                                 return (EBADRPC);
237                         hval = va_arg(args, uint64_t *);
238                         *hval = fxdr_hyper(tl);
239                         break;
240                 case 'o':       /* Fixed-length opaque */
241                         len = va_arg(args, uint32_t);
242                         p = va_arg(args, void *);
243                         tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
244                         if (tl == NULL)
245                                 return (EBADRPC);
246                         bcopy(tl, p, len);
247                         break;
248                 case 'O':       /* Variable-length opaque */
249                 case 's':       /* String */
250                         len = va_arg(args, uint32_t);
251                         p = va_arg(args, char *);
252                         tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
253                         if (tl == NULL)
254                                 return (EBADRPC);
255                         bcopy(tl, p, len);
256                         break;
257                 case 'k':       /* Skip bytes */
258                         len = va_arg(args, uint32_t);
259                         t1 = nfsm_adv_xx(nfsm_rndup(len), md, dpos);
260                         break;
261                 default:
262                         panic("Invalid dissectf string %s[%c]", fmt, *which);
263                         break;
264                 }
265         va_end(args);
266
267         return (0);
268 }
269
270 /*
271  * XXX - There are a few problems with the way the postops are places
272  * in the code.  Ideally, they should be taken care of immediately, as
273  * to avoid uneceesary waits for mutexes, but then we would be
274  * introducing even more complexity by having to handle two separate
275  * cases.  Also, since they are placed at the end of the vnops', there
276  * may be operations which sleep in between, further extending this
277  * wait.  It is conceivable that there is a deadlock condition there,
278  * too.
279  *
280  * Also, for vnops that do multiple operations, it's inconvenient
281  * since on error, individual decoding will got nfsmout.
282  */
283
284 int
285 nfs_v4postop(struct nfs4_compound *cp, int status)
286 {
287         struct nfs4_fctx *fcp = cp->fcp;
288
289         /*
290          * XXX does the previous result need to be stores with the
291          * lockowner?  ack, spec is unclear ..
292          */
293
294         if (fcp != NULL)
295                 if (cp->seqidused < cp->rep_nops ||
296                     (cp->seqidused + 1 == cp->rep_nops &&
297                         NFS4_SEQIDMUTATINGERROR(status)))
298                         fcp->lop->lo_seqid++;
299
300         return (status);
301 }
302
303 int
304 nfs_v4handlestatus(int status, struct nfs4_compound *cp)
305 {
306         return (status);
307 }
308
309 /*
310  * Initial setup of compound.
311  */
312
313 int
314 nfsm_v4build_compound_xx(struct nfs4_compound *cp, char *tag,
315     struct mbuf **mb, caddr_t *bpos)
316 {
317         uint32_t t1, *tl, siz;
318
319         /* Tag */
320         siz = strlen(tag);
321         t1 = nfsm_rndup(siz) + NFSX_UNSIGNED;
322         if (t1 <= M_TRAILINGSPACE(*mb)) {
323                 tl = nfsm_build_xx(t1, mb, bpos);
324                 *tl++ = txdr_unsigned(siz);
325                 *(tl + ((t1 >> 2) - 2)) = 0;
326                 bcopy(tag, tl, siz);
327         } else {
328                 t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz);
329                 if (t1 != 0)
330                         return (t1);
331         }
332
333         /* Minor version and argarray*/
334         tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
335         *tl++ = txdr_unsigned(NFS4_MINOR_VERSION);
336         /* Save for backfill */
337         cp->req_nopsp = tl;
338         *tl = txdr_unsigned(0);
339
340         cp->curvp = NULL;
341         cp->savevp = NULL;
342
343         return (0);
344 }
345
346 /*
347  * XXX
348  * - backfill for stateid, and such
349  */
350 int
351 nfsm_v4build_finalize_xx(struct nfs4_compound *cp, struct mbuf **mb, caddr_t *bpos)
352 {
353         *cp->req_nopsp = txdr_unsigned(cp->req_nops);
354
355         return (0);
356 }
357
358 int
359 nfsm_v4build_putfh_xx(struct nfs4_compound *cp, struct vnode *vp,
360     struct mbuf **mb, caddr_t *bpos)
361 {
362         uint32_t t1;
363
364         /* Op */
365         nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_PUTFH);
366
367         /* FH */
368         t1 = nfsm_fhtom_xx(vp, 1, mb, bpos);
369         if (t1 != 0)
370                 return (t1);
371
372         cp->req_nops++;
373         cp->curvp = vp;
374
375         return (0);
376 }
377
378 int
379 nfsm_v4build_putfh_nv_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
380     struct mbuf **mb, caddr_t *bpos)
381 {
382         nfsm_buildf_xx(mb, bpos, "uuo",
383             NFSV4OP_PUTFH,
384             gfh->fh_len,
385             gfh->fh_len,
386             &gfh->fh_val);
387
388         cp->req_nops++;
389
390         return (0);
391 }
392
393 int
394 nfsm_v4build_simple_xx(struct nfs4_compound *cp, uint32_t op,
395     struct mbuf **mb, caddr_t *bpos)
396 {
397         nfsm_buildf_xx(mb, bpos, "u", op);
398
399         cp->req_nops++;
400
401         return (0);
402 }
403
404 int
405 nfsm_v4build_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
406     struct mbuf **mb, caddr_t *bpos)
407 {
408         int i;
409
410         /* Op + bitmap length + bitmap */
411         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_GETATTR, ga->bm->bmlen);
412         for (i = 0; i < ga->bm->bmlen; i++)
413                 nfsm_buildf_xx(mb, bpos, "u", ga->bm->bmval[i]);
414
415         ga->vp = cp->curvp;
416         cp->req_nops++;          
417
418         return (0);
419 }
420
421 int
422 nfsm_v4build_setattr_xx(struct nfs4_compound *cp, struct vattr *vap,
423     struct nfs4_fctx *fcp, struct mbuf **mb, caddr_t *bpos)
424 {
425         int error;
426         static char zero_stateid[NFSX_V4STATEID];
427
428         nfsm_buildf_xx(mb, bpos, "uo",
429             NFSV4OP_SETATTR,
430             NFSX_V4STATEID, fcp ? fcp->stateid : zero_stateid);
431         error = nfsm_v4build_attrs_xx(vap, mb, bpos);
432         if (error == 0)
433                 cp->req_nops++;
434
435         return (error);
436 }
437
438 int
439 nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
440     struct mbuf **mb, caddr_t *bpos)
441 {
442         nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH);
443
444         gfh->vp = cp->curvp;
445         cp->req_nops++;
446
447         return (0);
448 }
449
450 int
451 nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l,
452     struct mbuf **mb, caddr_t *bpos)
453 {
454         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name);
455
456         cp->curvp = l->vp;
457         cp->req_nops++;
458
459         return (0);
460 }
461
462 int
463 nfsm_v4build_setclientid_xx(struct nfs4_compound *cp,
464     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
465 {
466         struct timeval tv;
467
468         microtime(&tv);
469
470         nfsm_buildf_xx(mb, bpos, "uuusussu",
471             NFSV4OP_SETCLIENTID,
472             tv.tv_sec, tv.tv_usec,
473             sci->namelen, sci->name,
474             sci->cb_prog,
475             sci->cb_netidlen, sci->cb_netid,
476             sci->cb_univaddrlen, sci->cb_univaddr,
477             0xCA11BACC);
478
479         cp->req_nops++;
480
481         return (0);
482 }
483
484 int
485 nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp,
486     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
487 {
488         nfsm_buildf_xx(mb, bpos, "uho",
489             NFSV4OP_SETCLIENTID_CONFIRM,
490             sci->clientid,
491             sizeof(sci->verf), sci->verf);
492
493         cp->req_nops++;
494
495         return (0);
496 }
497
498 int
499 nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
500     struct mbuf **mb, caddr_t *bpos)
501 {
502         int error = 0;
503         struct nfs4_lowner *lop = op->fcp->lop;
504
505         nfsm_buildf_xx(mb, bpos, "uuuuhuu",
506             NFSV4OP_OPEN,
507             lop->lo_seqid,
508             op->flags & O_ACCMODE,
509             NFSV4OPENSHARE_DENY_NONE,
510             cp->nmp->nm_clientid,
511             4, lop->lo_id);
512
513         if (op->flags & O_CREAT) {
514                 nfsm_buildf_xx(mb, bpos, "u", OTCREATE);
515                 /* openflag4: mode */
516                 nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED);
517                 /* openflag4: createattrs... */
518                 if (op->vap != NULL) {
519                         if (op->flags & O_TRUNC)
520                                 op->vap->va_size = 0;
521                         error = nfsm_v4build_attrs_xx(op->vap, mb, bpos);
522                         if (error != 0)
523                                 return (error);
524                 } else
525                         nfsm_buildf_xx(mb, bpos, "uu", 0, 0);
526         } else
527                 nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE);
528
529         nfsm_buildf_xx(mb, bpos, "us", op->ctype,
530             op->cnp->cn_namelen, op->cnp->cn_nameptr);
531
532         cp->seqidused = cp->req_nops++;
533         cp->fcp = op->fcp;
534
535         return (error);
536 }
537
538 /*
539  * XXX
540  * - Wait on recovery
541  */
542 int
543 nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
544     struct mbuf **mb, caddr_t *bpos)
545 {
546         nfsm_buildf_xx(mb, bpos, "uou",
547             NFSV4OP_OPEN_CONFIRM,
548             NFSX_V4STATEID, op->fcp->stateid,
549             op->fcp->lop->lo_seqid);
550
551         cp->seqidused = cp->req_nops++;
552         cp->fcp = op->fcp;
553
554         return (0);
555 }
556
557 /*
558  * XXX
559  * - Wait on recovery
560  */
561 int
562 nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
563     struct mbuf **mb, caddr_t *bpos)
564 {
565         struct nfs4_lowner *lop = fcp->lop;
566
567         nfsm_buildf_xx(mb, bpos, "uuo",
568             NFSV4OP_CLOSE,
569             lop->lo_seqid,
570             NFSX_V4STATEID, fcp->stateid);
571
572         cp->seqidused = cp->req_nops++;
573         cp->fcp = fcp;
574
575         return (0);
576 }
577
578 int
579 nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
580     struct mbuf **mb, caddr_t *bpos)
581 {
582         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode);
583         cp->req_nops++;
584
585         return (0);
586 }
587
588 int
589 nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
590     struct mbuf **mb, caddr_t *bpos)
591 {
592         nfsm_buildf_xx(mb, bpos, "uohu",
593             NFSV4OP_READ,
594             NFSX_V4STATEID, r->fcp->stateid,
595             r->off,
596             r->maxcnt);
597         cp->req_nops++;
598
599         return (0);
600 }
601
602 int
603 nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
604     struct mbuf **mb, caddr_t *bpos)
605 {
606         nfsm_buildf_xx(mb, bpos, "uohuu",
607             NFSV4OP_WRITE,
608             NFSX_V4STATEID, w->fcp->stateid,
609             w->off,
610             w->stable,
611             w->cnt);
612         cp->req_nops++;
613         return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos));
614 }
615
616 int
617 nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
618     struct mbuf **mb, caddr_t *bpos)
619 {
620         nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len);
621         cp->req_nops++;
622
623         return (0);
624 }
625
626 int
627 nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r,
628     struct mbuf **mb, caddr_t *bpos)
629 {
630         int i;
631
632         nfsm_buildf_xx(mb, bpos, "uhouuu",
633             NFSV4OP_READDIR,
634             r->cookie,
635             sizeof(r->verf), r->verf,
636             r->cnt >> 4,        /* meaningless "dircount" field */
637             r->cnt,
638             r->bm->bmlen);
639
640         for (i = 0; i < r->bm->bmlen; i++)
641                 nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]);
642
643         cp->req_nops++;
644
645         return (0);
646 }
647
648 int
649 nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid,
650     struct mbuf **mb, caddr_t *bpos)
651 {
652         nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid);
653         cp->req_nops++;
654
655         return (0);
656 }
657
658 int
659 nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
660     struct mbuf **mb, caddr_t *bpos)
661 {
662         uint32_t t1;
663
664         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type);
665
666         if (c->type == NFLNK)
667                 /* XXX strlen */
668                 nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext);
669         else if (c->type == NFCHR || c->type == NFBLK)
670                 nfsm_buildf_xx(mb, bpos, "uu",
671                     umajor(c->vap->va_rdev), uminor(c->vap->va_rdev));
672
673         /* Name */
674         nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name);     
675
676         /* Attributes */
677         t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos);
678         if (t1 != 0)
679                 return (t1);
680
681         cp->req_nops++;
682
683         return (0);
684 }
685
686 int
687 nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r,
688     struct mbuf **mb, caddr_t *bpos)
689 {
690         nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname,
691             r->tnamelen, r->tname);
692
693         cp->req_nops++;
694
695         return (0);
696 }
697
698 int
699 nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l,
700     struct mbuf **mb, caddr_t *bpos)
701 {
702         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name);
703
704         cp->req_nops++;
705
706         return (0);
707 }
708
709 int
710 nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen,
711     struct mbuf **mb, caddr_t *bpos)
712 {
713         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name);
714
715         cp->req_nops++;
716
717         return (0);
718 }
719
720 int
721 nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos)
722 {
723         uint32_t *tl, *attrlenp, *bmvalp, len;
724         size_t siz;
725
726         tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
727
728         *tl++ = txdr_unsigned(2);    /* bitmap length */
729         bmvalp = tl;
730         bzero(bmvalp, 8);
731         tl += 2;
732         attrlenp = tl;
733
734         len = 0;
735         if (vap->va_size != VNOVAL) {
736                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
737                 FA4_SET(FA4_SIZE, bmvalp);
738                 txdr_hyper(vap->va_size, tl); tl += 2;
739                 len += 2 * NFSX_UNSIGNED;
740         }
741         if (vap->va_mode != (u_short)VNOVAL) {
742                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
743                 FA4_SET(FA4_MODE, bmvalp);
744                 *tl++ = txdr_unsigned(vap->va_mode);
745                 len += NFSX_UNSIGNED;
746         }
747         if (vap->va_uid != VNOVAL) {
748                 int error;
749                 char *name;
750                 error = idmap_uid_to_name(vap->va_uid, &name, &siz);
751                 if (error || name == NULL || siz == 0) {
752                         /* XXX */
753                         siz = sizeof("nobody") - 1;
754                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
755                             bpos);
756                         *tl++ = txdr_unsigned(siz);
757                         bcopy("nobody", tl, siz);
758                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
759                 } else {
760                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
761                             bpos);
762                         *tl++ = txdr_unsigned(siz);
763                         bcopy(name, tl, siz);
764                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
765                 }
766                 FA4_SET(FA4_OWNER, bmvalp);
767         }
768         if (vap->va_gid != VNOVAL) {
769                 int error;
770                 char *name;
771                 error = idmap_gid_to_name(vap->va_gid, &name, &siz);
772                 if (error || name == NULL || siz == 0) {
773                         /* XXX */
774                         siz = sizeof("nogroup") - 1;
775                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
776                             bpos);
777                         *tl++ = txdr_unsigned(siz);
778                         bcopy("nogroup", tl, siz);
779                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
780                 } else {
781                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
782                             bpos);
783                         *tl++ = txdr_unsigned(siz);
784                         bcopy(name, tl, siz);
785                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
786                 }
787                 FA4_SET(FA4_OWNER_GROUP, bmvalp);
788         }
789         if (vap->va_atime.tv_sec != VNOVAL) {
790                 uint64_t val = vap->va_atime.tv_sec;
791                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
792                 FA4_SET(FA4_TIME_ACCESS_SET, bmvalp);
793                 *tl++ = txdr_unsigned(THCLIENTTIME);
794                 txdr_hyper(val, tl); tl += 2;
795                 *tl++ = txdr_unsigned(vap->va_atime.tv_nsec);
796                 len += 4 * NFSX_UNSIGNED;
797         }
798         if (vap->va_mtime.tv_sec != VNOVAL) {
799                 uint64_t val = vap->va_mtime.tv_sec;
800                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
801                 FA4_SET(FA4_TIME_MODIFY_SET, bmvalp);
802                 *tl++ = txdr_unsigned(THCLIENTTIME);
803                 txdr_hyper(val, tl); tl += 2;
804                 *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec);
805                 len += 4 * NFSX_UNSIGNED;
806         }
807
808         bmvalp[0] = txdr_unsigned(bmvalp[0]);
809         bmvalp[1] = txdr_unsigned(bmvalp[1]);
810
811         *attrlenp = txdr_unsigned(len);
812
813         return (0);
814 }
815
816 int
817 nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
818 {
819         uint32_t taglen, t1, *tl;
820
821         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
822         if (tl == NULL)
823                 return (EBADRPC);
824
825         /* Reply status is handled by the RPC code */
826
827         taglen = fxdr_unsigned(uint32_t, *tl++);
828         t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos);
829         if (t1 != 0)
830                 return (EBADRPC);
831
832         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
833         if (tl == NULL)
834                 return (EBADRPC);
835
836         cp->rep_nops = fxdr_unsigned(uint32_t, *tl++);
837
838         return (0);
839 }
840
841 int
842 nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op,
843     uint32_t skipbytes, struct mbuf **md, caddr_t *dpos)
844 {
845         uint32_t t1, dop, status;
846
847         t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status);
848         if (t1 != 0)
849                 return (t1);
850
851         if (dop != op || status != 0)
852                 return (EBADRPC);
853
854         if (skipbytes > 0)
855                 NFSM_ADV(nfsm_rndup(skipbytes));
856
857         return (0);
858 }
859
860 int
861 nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
862     struct mbuf **md, caddr_t *dpos)
863 {
864         uint32_t *tl;
865
866         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
867         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR ||
868             *tl++ != 0)
869                 return (EBADRPC);
870
871         return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos));
872 }
873
874 int
875 nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
876 {
877         uint32_t t1, op, bmlen, status;
878
879         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
880         if (t1 != 0)
881                 return (t1);
882
883         if (op != NFSV4OP_SETATTR || status != 0)
884                 return (EBADRPC);
885
886         t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen);
887         if (t1 != 0)
888                 return (t1);
889
890         return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2));
891 }
892
893 int
894 nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
895     struct mbuf **md, caddr_t *dpos)
896 {
897         uint32_t *tl, len, xdrlen;
898
899         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
900         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH)
901                 return (EBADRPC);
902
903         if (*tl++ != 0)
904                 return (EBADRPC);
905
906         NFSM_DISSECT(NFSX_UNSIGNED);
907         len = fxdr_unsigned(uint32_t, *tl++);
908         if (len > NFSX_V4FH)
909                 return (EBADRPC);
910
911         /* XXX integrate this into nfs_mtofh()? */
912
913         gfh->fh_len = len;
914         xdrlen = nfsm_rndup(len);
915
916         NFSM_DISSECT(xdrlen);
917         bcopy(tl, &gfh->fh_val, xdrlen);
918
919         return (0);
920 }
921
922 int
923 nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp,
924     struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos)
925 {
926         uint32_t *tl;
927
928         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
929         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID)
930                 return (EBADRPC);
931
932         /* Handle NFS4ERR_CLID_INUSE specially */
933         if (*tl++ != 0)
934                 return (EBADRPC);
935
936         NFSM_DISSECT(2 * NFSX_UNSIGNED);
937         sci->clientid = fxdr_hyper(tl);
938
939         NFSM_DISSECT(nfsm_rndup(NFSX_V4VERF));
940         bcopy(tl, sci->verf, NFSX_V4VERF);
941
942         return (0);
943 }
944
945 int
946 nfsm_v4dissect_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
947     struct mbuf **md, caddr_t *dpos)
948 {
949         uint32_t *tl, t1;
950
951         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
952         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_CLOSE ||
953             *tl++ != 0)
954                 return (EBADRPC);
955
956         /* Copy stateid */
957         t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
958         if (t1 != 0)
959                 return (t1);
960
961         return (0);
962 }
963
964 int
965 nfsm_v4dissect_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
966     struct mbuf **md, caddr_t *dpos)
967 {
968         uint32_t *tl;
969
970         tl = nfsm_dissect_xx(4 * NFSX_UNSIGNED, md, dpos);
971         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_ACCESS ||
972             *tl++ != 0)
973                 return (EBADRPC);
974
975         acc->supported = fxdr_unsigned(uint32_t, *tl++);
976         acc->rmode = fxdr_unsigned(uint32_t, *tl++);
977
978         return (0);
979 }
980
981 int
982 nfsm_v4dissect_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
983     struct mbuf **md, caddr_t *dpos)
984 {
985         uint32_t *tl, t1, bmlen, delegtype = ODNONE;
986         int error = 0;
987         nfsv4changeinfo cinfo;
988         struct nfs4_fctx *fcp = op->fcp;
989
990         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
991         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN ||
992             *tl++ != 0)
993                 return (EBADRPC);
994
995         t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
996         if (t1 != 0)
997                 return (t1);
998
999         error = nfsm_v4dissect_changeinfo_xx(&cinfo, md, dpos);
1000         if (error != 0)
1001                 goto nfsmout;
1002
1003         NFSM_DISSECT(2 * NFSX_UNSIGNED);
1004
1005         op->rflags = fxdr_unsigned(uint32_t, *tl++);
1006         bmlen = fxdr_unsigned(uint32_t, *tl++);
1007         if (bmlen > 2) {
1008                 error = EBADRPC;
1009                 goto nfsmout;
1010         }
1011
1012         /* Skip */
1013         NFSM_ADV(nfsm_rndup(bmlen << 2));
1014
1015         NFSM_DISSECT(NFSX_UNSIGNED);
1016         delegtype = fxdr_unsigned(uint32_t, *tl++);
1017         switch (delegtype) {
1018         case ODREAD:
1019         case ODWRITE:
1020                 printf("nfs4: client delegation not yet supported\n");
1021                 error = EOPNOTSUPP;
1022                 goto nfsmout;
1023                 break;
1024         case ODNONE:
1025         default:
1026                 break;
1027         }
1028
1029  nfsmout:
1030         return (error);
1031 }
1032
1033 int
1034 nfsm_v4dissect_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
1035     struct mbuf **md, caddr_t *dpos)
1036 {
1037         uint32_t *tl;
1038
1039         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1040         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN_CONFIRM ||
1041             *tl++ != 0)
1042                 return (EBADRPC);
1043
1044         return nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, op->fcp->stateid);
1045 }
1046
1047 int
1048 nfsm_v4dissect_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
1049     struct mbuf **md, caddr_t *dpos)
1050 {
1051         uint32_t op, status, t1;
1052
1053         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1054         if (t1 != 0)
1055                 return (t1);
1056
1057         if (op != NFSV4OP_READ || status != 0)
1058                 return (EBADRPC);
1059
1060         t1 = nfsm_dissectf_xx(md, dpos, "uu", &r->eof, &r->retlen);
1061         if (t1 != 0)
1062                 return (t1);
1063
1064         return (nfsm_mbuftouio(md, r->uiop, r->retlen, dpos));
1065 }
1066
1067 int
1068 nfsm_v4dissect_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
1069     struct mbuf **md, caddr_t *dpos)
1070 {
1071         uint32_t op, status, t1;
1072
1073         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1074         if (t1 != 0)
1075                 return (t1);
1076
1077         if (op != NFSV4OP_WRITE || status != 0)
1078                 return (EBADRPC);
1079
1080         return (nfsm_dissectf_xx(md, dpos, "uuo", &w->retlen, &w->committed,
1081                     NFSX_V4VERF, w->wverf));
1082 }
1083
1084 int
1085 nfsm_v4dissect_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
1086     struct mbuf **md, caddr_t *dpos)
1087 {
1088         uint32_t t1, op, status;
1089
1090         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1091         if (t1 != 0)
1092                 return (t1);
1093
1094         if (op != NFSV4OP_COMMIT || status != 0)
1095                 return (EBADRPC);
1096
1097         return (nfsm_dissectf_xx(md, dpos, "o", NFSX_V4VERF, c->verf));
1098 }
1099
1100 int
1101 nfsm_v4dissect_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
1102     struct mbuf **md, caddr_t *dpos)
1103 {
1104         uint32_t t1, *tl, op, status, bmlen;
1105         nfsv4changeinfo ci;
1106
1107         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1108         if (t1 != 0)
1109                 return (t1);
1110
1111         if (op != NFSV4OP_CREATE || status != 0)
1112                 return (EBADRPC);
1113
1114         /* Just throw this away for now */
1115         t1 = nfsm_v4dissect_changeinfo_xx(&ci, md, dpos);
1116         if (t1 != 0)
1117                 return (t1);
1118
1119         /* Throw this away too */
1120         NFSM_DISSECT(NFSX_UNSIGNED);
1121         bmlen = fxdr_unsigned(uint32_t, *tl++);
1122         NFSM_DISSECT(bmlen * NFSX_UNSIGNED);
1123         tl += bmlen;
1124
1125         return 0;
1126 }
1127
1128 int
1129 nfsm_v4dissect_readlink_xx(struct nfs4_compound *cp, struct uio *uiop, 
1130     struct mbuf **md, caddr_t *dpos)
1131 {
1132         uint32_t t1, *tl, op, status, linklen;
1133
1134         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1135         if (t1 != 0)
1136                 return (t1);
1137
1138         if (op != NFSV4OP_READLINK || status != 0)
1139                 return (EBADRPC);
1140
1141         /* Do this one manually for careful checking of sizes. */
1142         NFSM_DISSECT(NFSX_UNSIGNED);
1143         linklen = fxdr_unsigned(uint32_t, *tl++);
1144         if (linklen <= 0)
1145                 return (EBADRPC);
1146
1147         return (nfsm_mbuftouio(md, uiop, MIN(linklen, uiop->uio_resid), dpos));
1148 }
1149
1150 int
1151 nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *ci,
1152     struct mbuf **md, caddr_t *dpos)
1153 {
1154         uint32_t *tl;
1155
1156         NFSM_DISSECT(5 * NFSX_UNSIGNED);
1157
1158         ci->ciatomic = fxdr_unsigned(uint32_t, *tl++);
1159         ci->cibefore = fxdr_hyper(tl); tl += 2;
1160         ci->ciafter = fxdr_hyper(tl); tl += 2;
1161
1162         return (0);
1163 }
1164
1165 int
1166 nfsm_v4dissect_attrs_xx(struct nfsv4_fattr *fa, struct mbuf **md, caddr_t *dpos)
1167 {
1168         uint32_t t1, *tl, bmlen, bmval[2], attrlen, len = 0;
1169
1170         /* Bitmap length + value */
1171         NFSM_DISSECT(NFSX_UNSIGNED);
1172
1173         bmlen = fxdr_unsigned(uint32_t, *tl++);
1174         if (bmlen > 2)
1175                 return (EBADRPC);
1176
1177         if (bmlen == 0)
1178                 return (0);
1179
1180         NFSM_DISSECT(nfsm_rndup(bmlen << 2) + NFSX_UNSIGNED);
1181
1182         bmval[0] = bmlen > 0 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1183         bmval[1] = bmlen > 1 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1184
1185         /* Attribute length */
1186         attrlen = fxdr_unsigned(uint32_t, *tl++);
1187
1188         /*
1189          * XXX check for correct (<=) attributes mask return from
1190          * server.  need to pass this in.
1191          */
1192
1193         if (FA4_ISSET(FA4_TYPE, bmval)) {
1194                 /* overflow check */
1195                 NFSM_DISSECT(NFSX_UNSIGNED);
1196                 fa->fa4_type = fxdr_unsigned(uint32_t, *tl++);
1197                 fa->fa4_valid |= FA4V_TYPE;
1198                 len += NFSX_UNSIGNED;
1199         }
1200         if (FA4_ISSET(FA4_CHANGE, bmval)) {
1201                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1202                 fa->fa4_changeid = fxdr_hyper(tl);
1203                 fa->fa4_valid |= FA4V_CHANGEID;
1204                 len += 2 * NFSX_UNSIGNED;
1205         }
1206         if (FA4_ISSET(FA4_SIZE, bmval)) {
1207                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1208                 fa->fa4_size = fxdr_hyper(tl);
1209                 fa->fa4_valid |= FA4V_SIZE;
1210                 len += 2 * NFSX_UNSIGNED;
1211         }
1212         if (FA4_ISSET(FA4_FSID, bmval)) {
1213                 NFSM_DISSECT(4 * NFSX_UNSIGNED);
1214                 fa->fa4_fsid_major = fxdr_hyper(tl); tl += 2;
1215                 fa->fa4_fsid_minor = fxdr_hyper(tl);
1216                 fa->fa4_valid |= FA4V_SIZE;
1217                 len += 4 * NFSX_UNSIGNED;
1218         }
1219         if (FA4_ISSET(FA4_LEASE_TIME, bmval)) {
1220                 NFSM_DISSECT(NFSX_UNSIGNED);
1221                 fa->fa4_lease_time = fxdr_unsigned(uint32_t, *tl++);
1222                 fa->fa4_valid |= FA4V_LEASE_TIME;
1223                 len += NFSX_UNSIGNED;
1224         }
1225         if (FA4_ISSET(FA4_RDATTR_ERROR, bmval)) {
1226                 /* ignore for now; we only ask for it so the compound won't fail */
1227                 NFSM_DISSECT(NFSX_UNSIGNED);
1228                 tl++;
1229                 len += NFSX_UNSIGNED;
1230         }
1231         if (FA4_ISSET(FA4_FILEID, bmval)) {
1232                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1233                 fa->fa4_fileid = fxdr_hyper(tl);
1234                 fa->fa4_valid |= FA4V_FILEID;
1235                 len += 2 * NFSX_UNSIGNED;
1236         }
1237         if (FA4_ISSET(FA4_FILES_FREE, bmval)) {
1238                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1239                 fa->fa4_ffree = fxdr_hyper(tl);
1240                 fa->fa4_valid |= FA4V_FFREE;
1241                 len += 2 * NFSX_UNSIGNED;
1242         }
1243         if (FA4_ISSET(FA4_FILES_TOTAL, bmval)) {
1244                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1245                 fa->fa4_ftotal = fxdr_hyper(tl);
1246                 fa->fa4_valid |= FA4V_FTOTAL;
1247                 len += 2 * NFSX_UNSIGNED;
1248         }
1249         if (FA4_ISSET(FA4_MAXFILESIZE, bmval)) {
1250                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1251                 fa->fa4_maxfilesize = fxdr_hyper(tl);
1252                 fa->fa4_valid |= FA4V_MAXFILESIZE;
1253                 len += 2 * NFSX_UNSIGNED;
1254         }
1255         if (FA4_ISSET(FA4_MAXNAME, bmval)) {
1256                 NFSM_DISSECT(NFSX_UNSIGNED);
1257                 fa->fa4_maxname = fxdr_unsigned(uint32_t, *tl++);
1258                 fa->fa4_valid |= FA4V_MAXNAME;
1259                 len += NFSX_UNSIGNED;
1260         }
1261         if (FA4_ISSET(FA4_MAXREAD, bmval)) {
1262                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1263                 fa->fa4_maxread = fxdr_hyper(tl);
1264                 fa->fa4_valid |= FA4V_MAXREAD;
1265                 len += 2 * NFSX_UNSIGNED;
1266         }
1267         if (FA4_ISSET(FA4_MAXWRITE, bmval)) {
1268                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1269                 fa->fa4_maxwrite = fxdr_hyper(tl);
1270                 fa->fa4_valid |= FA4V_MAXWRITE;
1271                 len += 2 * NFSX_UNSIGNED;
1272         }
1273
1274         if (FA4_ISSET(FA4_MODE, bmval)) {
1275                 NFSM_DISSECT(NFSX_UNSIGNED);
1276                 fa->fa4_mode = fxdr_unsigned(mode_t, *tl++);
1277                 fa->fa4_valid |= FA4V_MODE;
1278                 len += NFSX_UNSIGNED;
1279         }
1280         if (FA4_ISSET(FA4_NUMLINKS, bmval)) {
1281                 NFSM_DISSECT(NFSX_UNSIGNED);
1282                 fa->fa4_nlink = fxdr_unsigned(nlink_t, *tl++);
1283                 fa->fa4_valid |= FA4V_NLINK;
1284                 len += NFSX_UNSIGNED;
1285         }
1286         if (FA4_ISSET(FA4_OWNER, bmval)) {
1287                 uint32_t ownerlen;
1288                 int error;
1289
1290                 NFSM_DISSECT(NFSX_UNSIGNED);
1291
1292                 ownerlen = fxdr_unsigned(uint32_t, *tl++);
1293                 NFSM_DISSECT(nfsm_rndup(ownerlen));
1294                 error = idmap_name_to_uid((char *)tl, ownerlen, &fa->fa4_uid);
1295                 if (error) 
1296                         fa->fa4_uid = -2;
1297                 fa->fa4_valid |= FA4V_UID;
1298                 len += NFSX_UNSIGNED + nfsm_rndup(ownerlen);
1299         }
1300         if (FA4_ISSET(FA4_OWNER_GROUP, bmval)) {
1301                 uint32_t ownergrouplen;
1302                 int error;
1303
1304                 NFSM_DISSECT(NFSX_UNSIGNED);
1305                 ownergrouplen = fxdr_unsigned(uint32_t, *tl++);
1306                 NFSM_DISSECT(nfsm_rndup(ownergrouplen));
1307                 error = idmap_name_to_gid((char *)tl, ownergrouplen, &fa->fa4_gid);
1308                 if (error) 
1309                         fa->fa4_gid = -2;
1310                 fa->fa4_valid |= FA4V_GID;
1311                 len += NFSX_UNSIGNED + nfsm_rndup(ownergrouplen);
1312         }
1313         if (FA4_ISSET(FA4_RAWDEV, bmval)) {
1314                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1315                 fa->fa4_rdev_major = fxdr_unsigned(uint32_t, *tl++);
1316                 fa->fa4_rdev_minor = fxdr_unsigned(uint32_t, *tl++);
1317                 fa->fa4_valid |= FA4V_RDEV;
1318                 len += 2 * NFSX_UNSIGNED;
1319         }
1320         if (FA4_ISSET(FA4_SPACE_AVAIL, bmval)) {
1321                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1322                 fa->fa4_savail = fxdr_hyper(tl);
1323                 fa->fa4_valid |= FA4V_SAVAIL;
1324                 len += 2 * NFSX_UNSIGNED;
1325         }
1326         if (FA4_ISSET(FA4_SPACE_FREE, bmval)) {
1327                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1328                 fa->fa4_sfree = fxdr_hyper(tl);
1329                 fa->fa4_valid |= FA4V_SFREE;
1330                 len += 2 * NFSX_UNSIGNED;
1331         }
1332         if (FA4_ISSET(FA4_SPACE_TOTAL, bmval)) {
1333                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1334                 fa->fa4_stotal = fxdr_hyper(tl);
1335                 fa->fa4_valid |= FA4V_STOTAL;
1336                 len += 2 * NFSX_UNSIGNED;
1337         }
1338         if (FA4_ISSET(FA4_SPACE_USED, bmval)) {
1339                 NFSM_ADV(2 * NFSX_UNSIGNED);
1340                 len += 2 * NFSX_UNSIGNED;
1341         }
1342         if (FA4_ISSET(FA4_TIME_ACCESS, bmval)) {
1343                 NFSM_MTOTIME(fa->fa4_atime);
1344                 fa->fa4_valid |= FA4V_ATIME;
1345                 len += 3 * NFSX_UNSIGNED;
1346         }
1347         if (FA4_ISSET(FA4_TIME_CREATE, bmval)) {
1348                 NFSM_MTOTIME(fa->fa4_btime);
1349                 fa->fa4_valid |= FA4V_BTIME;
1350                 len += 3 * NFSX_UNSIGNED;
1351         }
1352         if (FA4_ISSET(FA4_TIME_METADATA, bmval)) {
1353                 NFSM_MTOTIME(fa->fa4_ctime);
1354                 fa->fa4_valid |= FA4V_CTIME;
1355                 len += 3 * NFSX_UNSIGNED;
1356         }
1357         if (FA4_ISSET(FA4_TIME_MODIFY, bmval)) {
1358                 NFSM_MTOTIME(fa->fa4_mtime);
1359                 fa->fa4_valid |= FA4V_MTIME;
1360                 len += 3 * NFSX_UNSIGNED;
1361         }
1362
1363         if (len != attrlen)
1364                 return (EBADRPC);
1365
1366         return (0);
1367 }