2 /* $Id: nfs4_subs.c,v 1.52 2003/11/05 14:58:59 rees Exp $ */
6 * the regents of the university of michigan
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.
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.
28 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
36 #include <sys/mount.h>
37 #include <sys/vnode.h>
38 #include <sys/namei.h>
40 #include <sys/socket.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>
48 #include <machine/stdarg.h>
51 #include <vm/vm_object.h>
52 #include <vm/vm_extern.h>
55 #include <rpc/rpcclnt.h>
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>
66 #include <nfs4client/nfs4_dev.h>
67 #include <nfs4client/nfs4_idmap.h>
68 #include <nfs4client/nfs4m_subs.h>
70 #include <netinet/in.h>
72 #define NFSM_DISSECT(s) do { \
73 tl = nfsm_dissect_xx((s), md, dpos); \
75 printf("NFSM_DISSECT error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__); \
80 #define NFSM_ADV(s) do { \
81 t1 = nfsm_adv_xx((s), md, dpos); \
83 printf("NFSM_ADV error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__); \
88 #define NFSM_MTOTIME(t) do { \
89 NFSM_DISSECT(3 * NFSX_UNSIGNED); \
90 (t).tv_sec = fxdr_hyper(tl); \
92 (t).tv_nsec = fxdr_unsigned(long, *tl++); \
95 static uint32_t __fsinfo_bm[2], __fsattr_bm[2], __getattr_bm[2], __readdir_bm[2];
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 };
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 *);
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);
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);
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_MODIFY, __getattr_bm);
133 FA4_SET(FA4_TIME_ACCESS, __getattr_bm);
135 FA4_SET(FA4_TYPE, __readdir_bm);
136 FA4_SET(FA4_FSID, __readdir_bm);
137 FA4_SET(FA4_FILEID, __readdir_bm);
138 FA4_SET(FA4_RDATTR_ERROR, __readdir_bm);
146 nfs_v4fileid4_to_fileid(uint64_t fid)
148 return ((uint32_t)((fid >> 32) | fid));
152 nfs_v4initcompound(struct nfs4_compound *cp)
154 bzero(cp, sizeof(*cp));
158 * Build/dissect XDR buffer with a format string.
162 * s - stringlength, string
163 * k - skip length (bytes)
164 * a - arraylength, componentlenght, array
165 * o - opaque fix length
166 * O - opaque var length in bytes
170 nfsm_buildf_xx(struct mbuf **mb, caddr_t *bpos, char *fmt, ...)
172 uint32_t *tl, t1, len, uval;
178 for (which = fmt; *which != '\0'; which++)
180 case 'u': /* Unsigned */
181 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
182 uval = va_arg(args, uint32_t);
183 *tl++ = txdr_unsigned(uval);
185 case 'h': /* Hyper */
186 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
187 hval = va_arg(args, uint64_t);
188 txdr_hyper(hval, tl);
190 case 'o': /* Fixed-length opaque */
191 len = va_arg(args, uint32_t);
192 p = va_arg(args, char *);
193 tl = nfsm_build_xx(nfsm_rndup(len), mb, bpos);
196 case 'O': /* Variable-length opaque */
197 case 's': /* String */
198 len = va_arg(args, uint32_t);
199 p = va_arg(args, char *);
200 t1 = nfsm_strtom_xx(p, len, len, mb, bpos);
203 len = va_arg(args, uint32_t);
204 nfsm_build_xx(nfsm_rndup(len), mb, bpos);
207 panic("Invalid buildf string %s[%c]", fmt, *which);
214 nfsm_dissectf_xx(struct mbuf **md, caddr_t *dpos, char *fmt, ...)
216 uint32_t *tl, t1, len, *uval;
222 for (which = fmt; *which != '\0'; which++)
224 case 'u': /* Unsigned */
225 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
228 uval = va_arg(args, uint32_t *);
229 *uval = fxdr_unsigned(uint32_t, *tl++);
231 case 'h': /* Hyper */
232 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
235 hval = va_arg(args, uint64_t *);
236 *hval = fxdr_hyper(tl);
238 case 'o': /* Fixed-length opaque */
239 len = va_arg(args, uint32_t);
240 p = va_arg(args, void *);
241 tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
246 case 'O': /* Variable-length opaque */
247 case 's': /* String */
248 len = va_arg(args, uint32_t);
249 p = va_arg(args, char *);
250 tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
255 case 'k': /* Skip bytes */
256 len = va_arg(args, uint32_t);
257 t1 = nfsm_adv_xx(nfsm_rndup(len), md, dpos);
260 panic("Invalid dissectf string %s[%c]", fmt, *which);
269 * XXX - There are a few problems with the way the postops are places
270 * in the code. Ideally, they should be taken care of immediately, as
271 * to avoid uneceesary waits for mutexes, but then we would be
272 * introducing even more complexity by having to handle two separate
273 * cases. Also, since they are placed at the end of the vnops', there
274 * may be operations which sleep in between, further extending this
275 * wait. It is conceivable that there is a deadlock condition there,
278 * Also, for vnops that do multiple operations, it's inconvenient
279 * since on error, individual decoding will got nfsmout.
283 nfs_v4postop(struct nfs4_compound *cp, int status)
285 struct nfs4_fctx *fcp = cp->fcp;
288 * XXX does the previous result need to be stores with the
289 * lockowner? ack, spec is unclear ..
293 if (cp->seqidused < cp->rep_nops ||
294 (cp->seqidused + 1 == cp->rep_nops &&
295 NFS4_SEQIDMUTATINGERROR(status)))
296 fcp->lop->lo_seqid++;
302 nfs_v4handlestatus(int status, struct nfs4_compound *cp)
308 * Initial setup of compound.
312 nfsm_v4build_compound_xx(struct nfs4_compound *cp, char *tag,
313 struct mbuf **mb, caddr_t *bpos)
315 uint32_t t1, *tl, siz;
319 t1 = nfsm_rndup(siz) + NFSX_UNSIGNED;
320 if (t1 <= M_TRAILINGSPACE(*mb)) {
321 tl = nfsm_build_xx(t1, mb, bpos);
322 *tl++ = txdr_unsigned(siz);
323 *(tl + ((t1 >> 2) - 2)) = 0;
326 t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz);
331 /* Minor version and argarray*/
332 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
333 *tl++ = txdr_unsigned(NFS4_MINOR_VERSION);
334 /* Save for backfill */
336 *tl = txdr_unsigned(0);
346 * - backfill for stateid, and such
349 nfsm_v4build_finalize_xx(struct nfs4_compound *cp, struct mbuf **mb, caddr_t *bpos)
351 *cp->req_nopsp = txdr_unsigned(cp->req_nops);
357 nfsm_v4build_putfh_xx(struct nfs4_compound *cp, struct vnode *vp,
358 struct mbuf **mb, caddr_t *bpos)
363 nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_PUTFH);
366 t1 = nfsm_fhtom_xx(vp, 1, mb, bpos);
377 nfsm_v4build_putfh_nv_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
378 struct mbuf **mb, caddr_t *bpos)
380 nfsm_buildf_xx(mb, bpos, "uuo",
392 nfsm_v4build_simple_xx(struct nfs4_compound *cp, uint32_t op,
393 struct mbuf **mb, caddr_t *bpos)
395 nfsm_buildf_xx(mb, bpos, "u", op);
403 nfsm_v4build_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
404 struct mbuf **mb, caddr_t *bpos)
408 /* Op + bitmap length + bitmap */
409 nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_GETATTR, ga->bm->bmlen);
410 for (i = 0; i < ga->bm->bmlen; i++)
411 nfsm_buildf_xx(mb, bpos, "u", ga->bm->bmval[i]);
420 nfsm_v4build_setattr_xx(struct nfs4_compound *cp, struct vattr *vap,
421 struct nfs4_fctx *fcp, struct mbuf **mb, caddr_t *bpos)
425 nfsm_buildf_xx(mb, bpos, "uo",
427 NFSX_V4STATEID, fcp->stateid);
428 error = nfsm_v4build_attrs_xx(vap, mb, bpos);
436 nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
437 struct mbuf **mb, caddr_t *bpos)
439 nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH);
448 nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l,
449 struct mbuf **mb, caddr_t *bpos)
451 nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name);
460 nfsm_v4build_setclientid_xx(struct nfs4_compound *cp,
461 struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
467 nfsm_buildf_xx(mb, bpos, "uuusussu",
469 tv.tv_sec, tv.tv_usec,
470 sci->namelen, sci->name,
472 sci->cb_netidlen, sci->cb_netid,
473 sci->cb_univaddrlen, sci->cb_univaddr,
482 nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp,
483 struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
485 nfsm_buildf_xx(mb, bpos, "uho",
486 NFSV4OP_SETCLIENTID_CONFIRM,
488 sizeof(sci->verf), sci->verf);
496 nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
497 struct mbuf **mb, caddr_t *bpos)
500 struct nfs4_lowner *lop = op->fcp->lop;
502 nfsm_buildf_xx(mb, bpos, "uuuuhuu",
505 op->flags & O_ACCMODE,
506 NFSV4OPENSHARE_DENY_NONE,
507 cp->nmp->nm_clientid,
510 if (op->flags & O_CREAT) {
511 nfsm_buildf_xx(mb, bpos, "u", OTCREATE);
512 /* openflag4: mode */
513 nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED);
514 /* openflag4: createattrs... */
515 if (op->vap != NULL) {
516 if (op->flags & O_TRUNC)
517 op->vap->va_size = 0;
518 error = nfsm_v4build_attrs_xx(op->vap, mb, bpos);
522 nfsm_buildf_xx(mb, bpos, "uu", 0, 0);
524 nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE);
526 nfsm_buildf_xx(mb, bpos, "us", op->ctype,
527 op->cnp->cn_namelen, op->cnp->cn_nameptr);
529 cp->seqidused = cp->req_nops++;
540 nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
541 struct mbuf **mb, caddr_t *bpos)
543 nfsm_buildf_xx(mb, bpos, "uou",
544 NFSV4OP_OPEN_CONFIRM,
545 NFSX_V4STATEID, op->fcp->stateid,
546 op->fcp->lop->lo_seqid);
548 cp->seqidused = cp->req_nops++;
559 nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
560 struct mbuf **mb, caddr_t *bpos)
562 struct nfs4_lowner *lop = fcp->lop;
564 nfsm_buildf_xx(mb, bpos, "uuo",
567 NFSX_V4STATEID, fcp->stateid);
569 cp->seqidused = cp->req_nops++;
576 nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
577 struct mbuf **mb, caddr_t *bpos)
579 nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode);
586 nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
587 struct mbuf **mb, caddr_t *bpos)
589 nfsm_buildf_xx(mb, bpos, "uohu",
591 NFSX_V4STATEID, r->fcp->stateid,
600 nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
601 struct mbuf **mb, caddr_t *bpos)
603 nfsm_buildf_xx(mb, bpos, "uohuu",
605 NFSX_V4STATEID, w->fcp->stateid,
610 return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos));
614 nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
615 struct mbuf **mb, caddr_t *bpos)
617 nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len);
624 nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r,
625 struct mbuf **mb, caddr_t *bpos)
629 nfsm_buildf_xx(mb, bpos, "uhouuu",
632 sizeof(r->verf), r->verf,
633 r->cnt >> 4, /* meaningless "dircount" field */
637 for (i = 0; i < r->bm->bmlen; i++)
638 nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]);
646 nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid,
647 struct mbuf **mb, caddr_t *bpos)
649 nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid);
656 nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
657 struct mbuf **mb, caddr_t *bpos)
661 nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type);
663 if (c->type == NFLNK)
665 nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext);
666 else if (c->type == NFCHR || c->type == NFBLK)
667 nfsm_buildf_xx(mb, bpos, "uu",
668 umajor(c->vap->va_rdev), uminor(c->vap->va_rdev));
671 nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name);
674 t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos);
684 nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r,
685 struct mbuf **mb, caddr_t *bpos)
687 nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname,
688 r->tnamelen, r->tname);
696 nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l,
697 struct mbuf **mb, caddr_t *bpos)
699 nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name);
707 nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen,
708 struct mbuf **mb, caddr_t *bpos)
710 nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name);
718 nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos)
720 uint32_t *tl, *attrlenp, *bmvalp, len;
723 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
725 *tl++ = txdr_unsigned(2); /* bitmap length */
732 if (vap->va_size != VNOVAL) {
733 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
734 FA4_SET(FA4_SIZE, bmvalp);
735 txdr_hyper(vap->va_size, tl); tl += 2;
736 len += 2 * NFSX_UNSIGNED;
738 if (vap->va_mode != (u_short)VNOVAL) {
739 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
740 FA4_SET(FA4_MODE, bmvalp);
741 *tl++ = txdr_unsigned(vap->va_mode);
742 len += NFSX_UNSIGNED;
744 if (vap->va_uid != VNOVAL) {
747 error = idmap_uid_to_name(vap->va_uid, &name, &siz);
748 if (error || name == NULL || siz == 0) {
750 siz = sizeof("nobody") - 1;
751 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
753 *tl++ = txdr_unsigned(siz);
754 bcopy("nobody", tl, siz);
755 len += NFSX_UNSIGNED + nfsm_rndup(siz);
757 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
759 *tl++ = txdr_unsigned(siz);
760 bcopy(name, tl, siz);
761 len += NFSX_UNSIGNED + nfsm_rndup(siz);
763 FA4_SET(FA4_OWNER, bmvalp);
765 if (vap->va_gid != VNOVAL) {
768 error = idmap_gid_to_name(vap->va_gid, &name, &siz);
769 if (error || name == NULL || siz == 0) {
771 siz = sizeof("nogroup") - 1;
772 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
774 *tl++ = txdr_unsigned(siz);
775 bcopy("nogroup", tl, siz);
776 len += NFSX_UNSIGNED + nfsm_rndup(siz);
778 tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
780 *tl++ = txdr_unsigned(siz);
781 bcopy(name, tl, siz);
782 len += NFSX_UNSIGNED + nfsm_rndup(siz);
784 FA4_SET(FA4_OWNER_GROUP, bmvalp);
786 if (vap->va_atime.tv_sec != VNOVAL) {
787 uint64_t val = vap->va_atime.tv_sec;
788 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
789 FA4_SET(FA4_TIME_ACCESS_SET, bmvalp);
790 *tl++ = txdr_unsigned(THCLIENTTIME);
791 txdr_hyper(val, tl); tl += 2;
792 *tl++ = txdr_unsigned(vap->va_atime.tv_nsec);
793 len += 4 * NFSX_UNSIGNED;
795 if (vap->va_mtime.tv_sec != VNOVAL) {
796 uint64_t val = vap->va_mtime.tv_sec;
797 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
798 FA4_SET(FA4_TIME_MODIFY_SET, bmvalp);
799 *tl++ = txdr_unsigned(THCLIENTTIME);
800 txdr_hyper(val, tl); tl += 2;
801 *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec);
802 len += 4 * NFSX_UNSIGNED;
805 bmvalp[0] = txdr_unsigned(bmvalp[0]);
806 bmvalp[1] = txdr_unsigned(bmvalp[1]);
808 *attrlenp = txdr_unsigned(len);
814 nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
816 uint32_t taglen, t1, *tl;
818 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
822 /* Reply status is handled by the RPC code */
824 taglen = fxdr_unsigned(uint32_t, *tl++);
825 t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos);
829 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
833 cp->rep_nops = fxdr_unsigned(uint32_t, *tl++);
839 nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op,
840 uint32_t skipbytes, struct mbuf **md, caddr_t *dpos)
842 uint32_t t1, dop, status;
844 t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status);
848 if (dop != op || status != 0)
852 NFSM_ADV(nfsm_rndup(skipbytes));
858 nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
859 struct mbuf **md, caddr_t *dpos)
863 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
864 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR ||
868 return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos));
872 nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
874 uint32_t t1, op, bmlen, status;
876 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
880 if (op != NFSV4OP_SETATTR || status != 0)
883 t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen);
887 return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2));
891 nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
892 struct mbuf **md, caddr_t *dpos)
894 uint32_t *tl, len, xdrlen;
896 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
897 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH)
903 NFSM_DISSECT(NFSX_UNSIGNED);
904 len = fxdr_unsigned(uint32_t, *tl++);
908 /* XXX integrate this into nfs_mtofh()? */
911 xdrlen = nfsm_rndup(len);
913 NFSM_DISSECT(xdrlen);
914 bcopy(tl, &gfh->fh_val, xdrlen);
920 nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp,
921 struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos)
925 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
926 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID)
929 /* Handle NFS4ERR_CLID_INUSE specially */
933 NFSM_DISSECT(2 * NFSX_UNSIGNED);
934 sci->clientid = fxdr_hyper(tl);
936 NFSM_DISSECT(nfsm_rndup(NFSX_V4VERF));
937 bcopy(tl, sci->verf, NFSX_V4VERF);
943 nfsm_v4dissect_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
944 struct mbuf **md, caddr_t *dpos)
948 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
949 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_CLOSE ||
954 t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
962 nfsm_v4dissect_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
963 struct mbuf **md, caddr_t *dpos)
967 tl = nfsm_dissect_xx(4 * NFSX_UNSIGNED, md, dpos);
968 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_ACCESS ||
972 acc->supported = fxdr_unsigned(uint32_t, *tl++);
973 acc->rmode = fxdr_unsigned(uint32_t, *tl++);
979 nfsm_v4dissect_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
980 struct mbuf **md, caddr_t *dpos)
982 uint32_t *tl, t1, bmlen, delegtype = ODNONE;
984 nfsv4changeinfo cinfo;
985 struct nfs4_fctx *fcp = op->fcp;
987 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
988 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN ||
992 t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
996 error = nfsm_v4dissect_changeinfo_xx(&cinfo, md, dpos);
1000 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1002 op->rflags = fxdr_unsigned(uint32_t, *tl++);
1003 bmlen = fxdr_unsigned(uint32_t, *tl++);
1010 NFSM_ADV(nfsm_rndup(bmlen << 2));
1012 NFSM_DISSECT(NFSX_UNSIGNED);
1013 delegtype = fxdr_unsigned(uint32_t, *tl++);
1014 switch (delegtype) {
1017 printf("nfs4: client delegation not yet supported\n");
1031 nfsm_v4dissect_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
1032 struct mbuf **md, caddr_t *dpos)
1036 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1037 if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN_CONFIRM ||
1041 return nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, op->fcp->stateid);
1045 nfsm_v4dissect_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
1046 struct mbuf **md, caddr_t *dpos)
1048 uint32_t op, status, t1;
1050 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1054 if (op != NFSV4OP_READ || status != 0)
1057 t1 = nfsm_dissectf_xx(md, dpos, "uu", &r->eof, &r->retlen);
1061 return (nfsm_mbuftouio(md, r->uiop, r->retlen, dpos));
1065 nfsm_v4dissect_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
1066 struct mbuf **md, caddr_t *dpos)
1068 uint32_t op, status, t1;
1070 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1074 if (op != NFSV4OP_WRITE || status != 0)
1077 return (nfsm_dissectf_xx(md, dpos, "uuo", &w->retlen, &w->committed,
1078 NFSX_V4VERF, w->wverf));
1082 nfsm_v4dissect_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
1083 struct mbuf **md, caddr_t *dpos)
1085 uint32_t t1, op, status;
1087 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1091 if (op != NFSV4OP_COMMIT || status != 0)
1094 return (nfsm_dissectf_xx(md, dpos, "o", NFSX_V4VERF, c->verf));
1098 nfsm_v4dissect_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
1099 struct mbuf **md, caddr_t *dpos)
1101 uint32_t t1, *tl, op, status, bmlen;
1104 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1108 if (op != NFSV4OP_CREATE || status != 0)
1111 /* Just throw this away for now */
1112 t1 = nfsm_v4dissect_changeinfo_xx(&ci, md, dpos);
1116 /* Throw this away too */
1117 NFSM_DISSECT(NFSX_UNSIGNED);
1118 bmlen = fxdr_unsigned(uint32_t, *tl++);
1119 NFSM_DISSECT(bmlen * NFSX_UNSIGNED);
1126 nfsm_v4dissect_readlink_xx(struct nfs4_compound *cp, struct uio *uiop,
1127 struct mbuf **md, caddr_t *dpos)
1129 uint32_t t1, *tl, op, status, linklen;
1131 t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1135 if (op != NFSV4OP_READLINK || status != 0)
1138 /* Do this one manually for careful checking of sizes. */
1139 NFSM_DISSECT(NFSX_UNSIGNED);
1140 linklen = fxdr_unsigned(uint32_t, *tl++);
1144 return (nfsm_mbuftouio(md, uiop, MIN(linklen, uiop->uio_resid), dpos));
1148 nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *ci,
1149 struct mbuf **md, caddr_t *dpos)
1153 NFSM_DISSECT(5 * NFSX_UNSIGNED);
1155 ci->ciatomic = fxdr_unsigned(uint32_t, *tl++);
1156 ci->cibefore = fxdr_hyper(tl); tl += 2;
1157 ci->ciafter = fxdr_hyper(tl); tl += 2;
1163 nfsm_v4dissect_attrs_xx(struct nfsv4_fattr *fa, struct mbuf **md, caddr_t *dpos)
1165 uint32_t t1, *tl, bmlen, bmval[2], attrlen, len = 0;
1167 /* Bitmap length + value */
1168 NFSM_DISSECT(NFSX_UNSIGNED);
1170 bmlen = fxdr_unsigned(uint32_t, *tl++);
1177 NFSM_DISSECT(nfsm_rndup(bmlen << 2) + NFSX_UNSIGNED);
1179 bmval[0] = bmlen > 0 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1180 bmval[1] = bmlen > 1 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1182 /* Attribute length */
1183 attrlen = fxdr_unsigned(uint32_t, *tl++);
1186 * XXX check for correct (<=) attributes mask return from
1187 * server. need to pass this in.
1190 if (FA4_ISSET(FA4_TYPE, bmval)) {
1191 /* overflow check */
1192 NFSM_DISSECT(NFSX_UNSIGNED);
1193 fa->fa4_type = fxdr_unsigned(uint32_t, *tl++);
1194 fa->fa4_valid |= FA4V_TYPE;
1195 len += NFSX_UNSIGNED;
1197 if (FA4_ISSET(FA4_CHANGE, bmval)) {
1198 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1199 fa->fa4_changeid = fxdr_hyper(tl);
1200 fa->fa4_valid |= FA4V_CHANGEID;
1201 len += 2 * NFSX_UNSIGNED;
1203 if (FA4_ISSET(FA4_SIZE, bmval)) {
1204 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1205 fa->fa4_size = fxdr_hyper(tl);
1206 fa->fa4_valid |= FA4V_SIZE;
1207 len += 2 * NFSX_UNSIGNED;
1209 if (FA4_ISSET(FA4_FSID, bmval)) {
1210 NFSM_DISSECT(4 * NFSX_UNSIGNED);
1211 fa->fa4_fsid_major = fxdr_hyper(tl); tl += 2;
1212 fa->fa4_fsid_minor = fxdr_hyper(tl);
1213 fa->fa4_valid |= FA4V_SIZE;
1214 len += 4 * NFSX_UNSIGNED;
1216 if (FA4_ISSET(FA4_LEASE_TIME, bmval)) {
1217 NFSM_DISSECT(NFSX_UNSIGNED);
1218 fa->fa4_lease_time = fxdr_unsigned(uint32_t, *tl++);
1219 fa->fa4_valid |= FA4V_LEASE_TIME;
1220 len += NFSX_UNSIGNED;
1222 if (FA4_ISSET(FA4_RDATTR_ERROR, bmval)) {
1223 /* ignore for now; we only ask for it so the compound won't fail */
1224 NFSM_DISSECT(NFSX_UNSIGNED);
1226 len += NFSX_UNSIGNED;
1228 if (FA4_ISSET(FA4_FILEID, bmval)) {
1229 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1230 fa->fa4_fileid = fxdr_hyper(tl);
1231 fa->fa4_valid |= FA4V_FILEID;
1232 len += 2 * NFSX_UNSIGNED;
1234 if (FA4_ISSET(FA4_FILES_FREE, bmval)) {
1235 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1236 fa->fa4_ffree = fxdr_hyper(tl);
1237 fa->fa4_valid |= FA4V_FFREE;
1238 len += 2 * NFSX_UNSIGNED;
1240 if (FA4_ISSET(FA4_FILES_TOTAL, bmval)) {
1241 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1242 fa->fa4_ftotal = fxdr_hyper(tl);
1243 fa->fa4_valid |= FA4V_FTOTAL;
1244 len += 2 * NFSX_UNSIGNED;
1246 if (FA4_ISSET(FA4_MAXFILESIZE, bmval)) {
1247 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1248 fa->fa4_maxfilesize = fxdr_hyper(tl);
1249 fa->fa4_valid |= FA4V_MAXFILESIZE;
1250 len += 2 * NFSX_UNSIGNED;
1252 if (FA4_ISSET(FA4_MAXNAME, bmval)) {
1253 NFSM_DISSECT(NFSX_UNSIGNED);
1254 fa->fa4_maxname = fxdr_unsigned(uint32_t, *tl++);
1255 fa->fa4_valid |= FA4V_MAXNAME;
1256 len += NFSX_UNSIGNED;
1258 if (FA4_ISSET(FA4_MAXREAD, bmval)) {
1259 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1260 fa->fa4_maxread = fxdr_hyper(tl);
1261 fa->fa4_valid |= FA4V_MAXREAD;
1262 len += 2 * NFSX_UNSIGNED;
1264 if (FA4_ISSET(FA4_MAXWRITE, bmval)) {
1265 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1266 fa->fa4_maxwrite = fxdr_hyper(tl);
1267 fa->fa4_valid |= FA4V_MAXWRITE;
1268 len += 2 * NFSX_UNSIGNED;
1271 if (FA4_ISSET(FA4_MODE, bmval)) {
1272 NFSM_DISSECT(NFSX_UNSIGNED);
1273 fa->fa4_mode = fxdr_unsigned(mode_t, *tl++);
1274 fa->fa4_valid |= FA4V_MODE;
1275 len += NFSX_UNSIGNED;
1277 if (FA4_ISSET(FA4_NUMLINKS, bmval)) {
1278 NFSM_DISSECT(NFSX_UNSIGNED);
1279 fa->fa4_nlink = fxdr_unsigned(nlink_t, *tl++);
1280 fa->fa4_valid |= FA4V_NLINK;
1281 len += NFSX_UNSIGNED;
1283 if (FA4_ISSET(FA4_OWNER, bmval)) {
1287 NFSM_DISSECT(NFSX_UNSIGNED);
1289 ownerlen = fxdr_unsigned(uint32_t, *tl++);
1290 NFSM_DISSECT(nfsm_rndup(ownerlen));
1291 error = idmap_name_to_uid((char *)tl, ownerlen, &fa->fa4_uid);
1294 fa->fa4_valid |= FA4V_UID;
1295 len += NFSX_UNSIGNED + nfsm_rndup(ownerlen);
1297 if (FA4_ISSET(FA4_OWNER_GROUP, bmval)) {
1298 uint32_t ownergrouplen;
1301 NFSM_DISSECT(NFSX_UNSIGNED);
1302 ownergrouplen = fxdr_unsigned(uint32_t, *tl++);
1303 NFSM_DISSECT(nfsm_rndup(ownergrouplen));
1304 error = idmap_name_to_gid((char *)tl, ownergrouplen, &fa->fa4_gid);
1307 fa->fa4_valid |= FA4V_GID;
1308 len += NFSX_UNSIGNED + nfsm_rndup(ownergrouplen);
1310 if (FA4_ISSET(FA4_RAWDEV, bmval)) {
1311 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1312 fa->fa4_rdev_major = fxdr_unsigned(uint32_t, *tl++);
1313 fa->fa4_rdev_minor = fxdr_unsigned(uint32_t, *tl++);
1314 fa->fa4_valid |= FA4V_RDEV;
1315 len += 2 * NFSX_UNSIGNED;
1317 if (FA4_ISSET(FA4_SPACE_AVAIL, bmval)) {
1318 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1319 fa->fa4_savail = fxdr_hyper(tl);
1320 fa->fa4_valid |= FA4V_SAVAIL;
1321 len += 2 * NFSX_UNSIGNED;
1323 if (FA4_ISSET(FA4_SPACE_FREE, bmval)) {
1324 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1325 fa->fa4_sfree = fxdr_hyper(tl);
1326 fa->fa4_valid |= FA4V_SFREE;
1327 len += 2 * NFSX_UNSIGNED;
1329 if (FA4_ISSET(FA4_SPACE_TOTAL, bmval)) {
1330 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1331 fa->fa4_stotal = fxdr_hyper(tl);
1332 fa->fa4_valid |= FA4V_STOTAL;
1333 len += 2 * NFSX_UNSIGNED;
1335 if (FA4_ISSET(FA4_SPACE_USED, bmval)) {
1336 NFSM_ADV(2 * NFSX_UNSIGNED);
1337 len += 2 * NFSX_UNSIGNED;
1339 if (FA4_ISSET(FA4_TIME_ACCESS, bmval)) {
1340 NFSM_MTOTIME(fa->fa4_atime);
1341 fa->fa4_valid |= FA4V_ATIME;
1342 len += 3 * NFSX_UNSIGNED;
1344 if (FA4_ISSET(FA4_TIME_CREATE, bmval)) {
1345 NFSM_MTOTIME(fa->fa4_ctime);
1346 fa->fa4_valid |= FA4V_CTIME;
1347 len += 3 * NFSX_UNSIGNED;
1349 if (FA4_ISSET(FA4_TIME_MODIFY, bmval)) {
1350 NFSM_MTOTIME(fa->fa4_mtime);
1351 fa->fa4_valid |= FA4V_MTIME;
1352 len += 3 * NFSX_UNSIGNED;