diff options
author | alfred <alfred@FreeBSD.org> | 2003-11-14 20:54:10 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2003-11-14 20:54:10 +0000 |
commit | 5b076fe9da6e7bfd69aca6e09e64d75d72477b92 (patch) | |
tree | 551663ad558af360faf7b32b0b3e67a667de012c /sys/nfs4client/nfs4_subs.c | |
parent | af7f62665d5a48d63d7f4c984c6511297dbb645c (diff) | |
download | FreeBSD-src-5b076fe9da6e7bfd69aca6e09e64d75d72477b92.zip FreeBSD-src-5b076fe9da6e7bfd69aca6e09e64d75d72477b92.tar.gz |
University of Michigan's Citi NFSv4 kernel client code.
Submitted by: Jim Rees <rees@umich.edu>
Diffstat (limited to 'sys/nfs4client/nfs4_subs.c')
-rw-r--r-- | sys/nfs4client/nfs4_subs.c | 1352 |
1 files changed, 1352 insertions, 0 deletions
diff --git a/sys/nfs4client/nfs4_subs.c b/sys/nfs4client/nfs4_subs.c new file mode 100644 index 0000000..22ccfa8 --- /dev/null +++ b/sys/nfs4client/nfs4_subs.c @@ -0,0 +1,1352 @@ +/* $FreeBSD$ */ +/* $Id: nfs4_subs.c,v 1.52 2003/11/05 14:58:59 rees Exp $ */ + +/* + * copyright (c) 2003 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and redistribute + * this software and such derivative works for any purpose, so long as the name + * of the university of michigan is not used in any advertising or publicity + * pertaining to the use or distribution of this software without specific, + * written prior authorization. if the above copyright notice or any other + * identification of the university of michigan is included in any copy of any + * portion of this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the university + * of michigan as to its fitness for any purpose, and without warranty by the + * university of michigan of any kind, either express or implied, including + * without limitation the implied warranties of merchantability and fitness for + * a particular purpose. the regents of the university of michigan shall not be + * liable for any damages, including special, indirect, incidental, or + * consequential damages, with respect to any claim arising out of or in + * connection with the use of the software, even if it has been or is hereafter + * advised of the possibility of such damages. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bio.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/mount.h> +#include <sys/vnode.h> +#include <sys/namei.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/malloc.h> +#include <sys/sysent.h> +#include <sys/syscall.h> +#include <sys/sysproto.h> +#include <sys/fcntl.h> + +#include <machine/stdarg.h> + +#include <vm/vm.h> +#include <vm/vm_object.h> +#include <vm/vm_extern.h> +#include <vm/uma.h> + +#include <rpc/rpcclnt.h> + +#include <nfs/rpcv2.h> +#include <nfs/nfsproto.h> +#include <nfsclient/nfs.h> +#include <nfs4client/nfs4.h> +#include <nfsclient/nfsnode.h> +#include <nfsclient/nfsmount.h> +#include <nfs/xdr_subs.h> +#include <nfsclient/nfsm_subs.h> + +#include <nfs4client/nfs4_dev.h> +#include <nfs4client/nfs4_idmap.h> +#include <nfs4client/nfs4m_subs.h> + +#include <netinet/in.h> + +#define NFSM_DISSECT(s) do { \ + tl = nfsm_dissect_xx((s), md, dpos); \ + if (tl == NULL) { \ + printf("NFSM_DISSECT error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__); \ + return (EBADRPC); \ + } \ +} while (0) + +#define NFSM_ADV(s) do { \ + t1 = nfsm_adv_xx((s), md, dpos); \ + if (t1 != 0) { \ + printf("NFSM_ADV error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__); \ + return (EBADRPC); \ + } \ +} while (0) + +#define NFSM_MTOTIME(t) do { \ + NFSM_DISSECT(3 * NFSX_UNSIGNED); \ + (t).tv_sec = fxdr_hyper(tl); \ + tl += 2; \ + (t).tv_nsec = fxdr_unsigned(long, *tl++); \ +} while (0) + +static uint32_t __fsinfo_bm[2], __fsattr_bm[2], __getattr_bm[2], __readdir_bm[2]; + +nfsv4bitmap nfsv4_fsinfobm = { 2, __fsinfo_bm }; +nfsv4bitmap nfsv4_fsattrbm = { 2, __fsattr_bm }; +nfsv4bitmap nfsv4_getattrbm = { 2, __getattr_bm }; +nfsv4bitmap nfsv4_readdirbm = { 2, __readdir_bm }; + +/* Helper routines */ +int nfsm_v4build_attrs_xx(struct vattr *, struct mbuf **, caddr_t *); +int nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *, struct mbuf **, caddr_t *); + +void +nfsm_v4init(void) +{ + + /* Set up bitmasks */ + FA4_SET(FA4_FSID, __fsinfo_bm); + FA4_SET(FA4_MAXREAD, __fsinfo_bm); + FA4_SET(FA4_MAXWRITE, __fsinfo_bm); + FA4_SET(FA4_LEASE_TIME, __fsinfo_bm); + + FA4_SET(FA4_FSID, __fsattr_bm); + FA4_SET(FA4_FILES_FREE, __fsattr_bm); + FA4_SET(FA4_FILES_TOTAL, __fsattr_bm); + FA4_SET(FA4_SPACE_AVAIL, __fsattr_bm); + FA4_SET(FA4_SPACE_FREE, __fsattr_bm); + FA4_SET(FA4_SPACE_TOTAL, __fsattr_bm); + + FA4_SET(FA4_TYPE, __getattr_bm); + FA4_SET(FA4_FSID, __getattr_bm); + FA4_SET(FA4_SIZE, __getattr_bm); + FA4_SET(FA4_MODE, __getattr_bm); + FA4_SET(FA4_RAWDEV, __getattr_bm); + FA4_SET(FA4_NUMLINKS, __getattr_bm); + FA4_SET(FA4_OWNER, __getattr_bm); + FA4_SET(FA4_OWNER_GROUP, __getattr_bm); + FA4_SET(FA4_FILEID, __getattr_bm); + FA4_SET(FA4_TIME_MODIFY, __getattr_bm); + FA4_SET(FA4_TIME_ACCESS, __getattr_bm); +/* FA4_SET(FA4_TIME_CREATE, __getattr_bm);*/ + + FA4_SET(FA4_TYPE, __readdir_bm); + FA4_SET(FA4_FSID, __readdir_bm); + FA4_SET(FA4_FILEID, __readdir_bm); +} + +/* + * Util + */ + +uint32_t +nfs_v4fileid4_to_fileid(uint64_t fid) +{ + return ((uint32_t)((fid >> 32) | fid)); +} + +void +nfs_v4initcompound(struct nfs4_compound *cp) +{ + bzero(cp, sizeof(*cp)); +} + +/* + * Build/dissect XDR buffer with a format string. + * + * u - unsigned + * h - hyper + * s - stringlength, string + * k - skip length (bytes) + * a - arraylength, componentlenght, array + * o - opaque fix length + * O - opaque var length in bytes + */ + +void +nfsm_buildf_xx(struct mbuf **mb, caddr_t *bpos, char *fmt, ...) +{ + uint32_t *tl, t1, len, uval; + uint64_t hval; + va_list args; + char *p, *which; + + va_start(args, fmt); + for (which = fmt; *which != '\0'; which++) + switch (*which) { + case 'u': /* Unsigned */ + tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); + uval = va_arg(args, uint32_t); + *tl++ = txdr_unsigned(uval); + break; + case 'h': /* Hyper */ + tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); + hval = va_arg(args, uint64_t); + txdr_hyper(hval, tl); + break; + case 'o': /* Fixed-length opaque */ + len = va_arg(args, uint32_t); + p = va_arg(args, char *); + tl = nfsm_build_xx(nfsm_rndup(len), mb, bpos); + bcopy(p, tl, len); + break; + case 'O': /* Variable-length opaque */ + case 's': /* String */ + len = va_arg(args, uint32_t); + p = va_arg(args, char *); + t1 = nfsm_strtom_xx(p, len, len, mb, bpos); + break; + case 'k': /* Skip */ + len = va_arg(args, uint32_t); + nfsm_build_xx(nfsm_rndup(len), mb, bpos); + break; + default: + panic("Invalid buildf string %s[%c]", fmt, *which); + break; + } + va_end(args); +} + +int +nfsm_dissectf_xx(struct mbuf **md, caddr_t *dpos, char *fmt, ...) +{ + uint32_t *tl, t1, len, *uval; + uint64_t *hval; + va_list args; + char *p, *which; + + va_start(args, fmt); + for (which = fmt; *which != '\0'; which++) + switch (*which) { + case 'u': /* Unsigned */ + tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); + if (tl == NULL) + return (EBADRPC); + uval = va_arg(args, uint32_t *); + *uval = fxdr_unsigned(uint32_t, *tl++); + break; + case 'h': /* Hyper */ + tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL) + return (EBADRPC); + hval = va_arg(args, uint64_t *); + *hval = fxdr_hyper(tl); + break; + case 'o': /* Fixed-length opaque */ + len = va_arg(args, uint32_t); + p = va_arg(args, void *); + tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos); + if (tl == NULL) + return (EBADRPC); + bcopy(tl, p, len); + break; + case 'O': /* Variable-length opaque */ + case 's': /* String */ + len = va_arg(args, uint32_t); + p = va_arg(args, char *); + tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos); + if (tl == NULL) + return (EBADRPC); + bcopy(tl, p, len); + break; + case 'k': /* Skip bytes */ + len = va_arg(args, uint32_t); + t1 = nfsm_adv_xx(nfsm_rndup(len), md, dpos); + break; + default: + panic("Invalid dissectf string %s[%c]", fmt, *which); + break; + } + va_end(args); + + return (0); +} + +/* + * XXX - There are a few problems with the way the postops are places + * in the code. Ideally, they should be taken care of immediately, as + * to avoid uneceesary waits for mutexes, but then we would be + * introducing even more complexity by having to handle two separate + * cases. Also, since they are placed at the end of the vnops', there + * may be operations which sleep in between, further extending this + * wait. It is conceivable that there is a deadlock condition there, + * too. + * + * Also, for vnops that do multiple operations, it's inconvenient + * since on error, individual decoding will got nfsmout. + */ + +int +nfs_v4postop(struct nfs4_compound *cp, int status) +{ + struct nfs4_fctx *fcp = cp->fcp; + + /* + * XXX does the previous result need to be stores with the + * lockowner? ack, spec is unclear .. + */ + + if (fcp != NULL) + if (cp->seqidused < cp->rep_nops || + (cp->seqidused + 1 == cp->rep_nops && + NFS4_SEQIDMUTATINGERROR(status))) + fcp->lop->lo_seqid++; + + return (status); +} + +int +nfs_v4handlestatus(int status, struct nfs4_compound *cp) +{ + return (status); +} + +/* + * Initial setup of compound. + */ + +int +nfsm_v4build_compound_xx(struct nfs4_compound *cp, char *tag, + struct mbuf **mb, caddr_t *bpos) +{ + uint32_t t1, *tl, siz; + + /* Tag */ + siz = strlen(tag); + t1 = nfsm_rndup(siz) + NFSX_UNSIGNED; + if (t1 <= M_TRAILINGSPACE(*mb)) { + tl = nfsm_build_xx(t1, mb, bpos); + *tl++ = txdr_unsigned(siz); + *(tl + ((t1 >> 2) - 2)) = 0; + bcopy(tag, tl, siz); + } else { + t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz); + if (t1 != 0) + return (t1); + } + + /* Minor version and argarray*/ + tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); + *tl++ = txdr_unsigned(NFS4_MINOR_VERSION); + /* Save for backfill */ + cp->req_nopsp = tl; + *tl = txdr_unsigned(0); + + cp->curvp = NULL; + cp->savevp = NULL; + + return (0); +} + +/* + * XXX + * - backfill for stateid, and such + */ +int +nfsm_v4build_finalize_xx(struct nfs4_compound *cp, struct mbuf **mb, caddr_t *bpos) +{ + *cp->req_nopsp = txdr_unsigned(cp->req_nops); + + return (0); +} + +int +nfsm_v4build_putfh_xx(struct nfs4_compound *cp, struct vnode *vp, + struct mbuf **mb, caddr_t *bpos) +{ + uint32_t t1; + + /* Op */ + nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_PUTFH); + + /* FH */ + t1 = nfsm_fhtom_xx(vp, 1, mb, bpos); + if (t1 != 0) + return (t1); + + cp->req_nops++; + cp->curvp = vp; + + return (0); +} + +int +nfsm_v4build_putfh_nv_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uuo", + NFSV4OP_PUTFH, + gfh->fh_len, + gfh->fh_len, + &gfh->fh_val); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_simple_xx(struct nfs4_compound *cp, uint32_t op, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "u", op); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga, + struct mbuf **mb, caddr_t *bpos) +{ + int i; + + /* Op + bitmap length + bitmap */ + nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_GETATTR, ga->bm->bmlen); + for (i = 0; i < ga->bm->bmlen; i++) + nfsm_buildf_xx(mb, bpos, "u", ga->bm->bmval[i]); + + ga->vp = cp->curvp; + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_setattr_xx(struct nfs4_compound *cp, struct vattr *vap, + struct nfs4_fctx *fcp, struct mbuf **mb, caddr_t *bpos) +{ + int error; + + nfsm_buildf_xx(mb, bpos, "uo", + NFSV4OP_SETATTR, + NFSX_V4STATEID, fcp->stateid); + error = nfsm_v4build_attrs_xx(vap, mb, bpos); + if (error == 0) + cp->req_nops++; + + return (error); +} + +int +nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH); + + gfh->vp = cp->curvp; + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name); + + cp->curvp = l->vp; + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_setclientid_xx(struct nfs4_compound *cp, + struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos) +{ + struct timeval tv; + + microtime(&tv); + + nfsm_buildf_xx(mb, bpos, "uuusussu", + NFSV4OP_SETCLIENTID, + tv.tv_sec, tv.tv_usec, + sci->namelen, sci->name, + sci->cb_prog, + sci->cb_netidlen, sci->cb_netid, + sci->cb_univaddrlen, sci->cb_univaddr, + 0xCA11BACC); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp, + struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uho", + NFSV4OP_SETCLIENTID_CONFIRM, + sci->clientid, + sizeof(sci->verf), sci->verf); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op, + struct mbuf **mb, caddr_t *bpos) +{ + int error = 0; + struct nfs4_lowner *lop = op->fcp->lop; + + nfsm_buildf_xx(mb, bpos, "uuuuhuu", + NFSV4OP_OPEN, + lop->lo_seqid, + op->flags & O_ACCMODE, + NFSV4OPENSHARE_DENY_NONE, + cp->nmp->nm_clientid, + 4, lop->lo_id); + + if (op->flags & O_CREAT) { + nfsm_buildf_xx(mb, bpos, "u", OTCREATE); + /* openflag4: mode */ + nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED); + /* openflag4: createattrs... */ + if (op->vap != NULL) { + if (op->flags & O_TRUNC) + op->vap->va_size = 0; + error = nfsm_v4build_attrs_xx(op->vap, mb, bpos); + if (error != 0) + return (error); + } else + nfsm_buildf_xx(mb, bpos, "uu", 0, 0); + } else + nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE); + + nfsm_buildf_xx(mb, bpos, "us", op->ctype, + op->cnp->cn_namelen, op->cnp->cn_nameptr); + + cp->seqidused = cp->req_nops++; + cp->fcp = op->fcp; + + return (error); +} + +/* + * XXX + * - Wait on recovery + */ +int +nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uou", + NFSV4OP_OPEN_CONFIRM, + NFSX_V4STATEID, op->fcp->stateid, + op->fcp->lop->lo_seqid); + + cp->seqidused = cp->req_nops++; + cp->fcp = op->fcp; + + return (0); +} + +/* + * XXX + * - Wait on recovery + */ +int +nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp, + struct mbuf **mb, caddr_t *bpos) +{ + struct nfs4_lowner *lop = fcp->lop; + + nfsm_buildf_xx(mb, bpos, "uuo", + NFSV4OP_CLOSE, + lop->lo_seqid, + NFSX_V4STATEID, fcp->stateid); + + cp->seqidused = cp->req_nops++; + cp->fcp = fcp; + + return (0); +} + +int +nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode); + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uohu", + NFSV4OP_READ, + NFSX_V4STATEID, r->fcp->stateid, + r->off, + r->maxcnt); + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uohuu", + NFSV4OP_WRITE, + NFSX_V4STATEID, w->fcp->stateid, + w->off, + w->stable, + w->cnt); + cp->req_nops++; + return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos)); +} + +int +nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len); + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r, + struct mbuf **mb, caddr_t *bpos) +{ + int i; + + nfsm_buildf_xx(mb, bpos, "uhouuu", + NFSV4OP_READDIR, + r->cookie, + sizeof(r->verf), r->verf, + r->cnt >> 4, /* meaningless "dircount" field */ + r->cnt, + r->bm->bmlen); + + for (i = 0; i < r->bm->bmlen; i++) + nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid); + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c, + struct mbuf **mb, caddr_t *bpos) +{ + uint32_t t1; + + nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type); + + if (c->type == NFLNK) + /* XXX strlen */ + nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext); + else if (c->type == NFCHR || c->type == NFBLK) + nfsm_buildf_xx(mb, bpos, "uu", + umajor(c->vap->va_rdev), uminor(c->vap->va_rdev)); + + /* Name */ + nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name); + + /* Attributes */ + t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos); + if (t1 != 0) + return (t1); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname, + r->tnamelen, r->tname); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen, + struct mbuf **mb, caddr_t *bpos) +{ + nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name); + + cp->req_nops++; + + return (0); +} + +int +nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos) +{ + uint32_t *tl, *attrlenp, *bmvalp, siz, len; + + tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos); + + *tl++ = txdr_unsigned(2); /* bitmap length */ + bmvalp = tl; + bzero(bmvalp, 8); + tl += 2; + attrlenp = tl; + + len = 0; + if (vap->va_size != VNOVAL) { + tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); + FA4_SET(FA4_SIZE, bmvalp); + txdr_hyper(vap->va_size, tl); tl += 2; + len += 2 * NFSX_UNSIGNED; + } + if (vap->va_mode != (u_short)VNOVAL) { + tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); + FA4_SET(FA4_MODE, bmvalp); + *tl++ = txdr_unsigned(vap->va_mode); + len += NFSX_UNSIGNED; + } + if (vap->va_uid != VNOVAL) { + int error; + char *name; + error = idmap_uid_to_name(vap->va_uid, &name, &siz); + if (error || name == NULL || siz == 0) { + /* XXX */ + siz = sizeof("nobody") - 1; + tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, + bpos); + *tl++ = txdr_unsigned(siz); + bcopy("nobody", tl, siz); + len += NFSX_UNSIGNED + nfsm_rndup(siz); + } else { + tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, + bpos); + *tl++ = txdr_unsigned(siz); + bcopy(name, tl, siz); + len += NFSX_UNSIGNED + nfsm_rndup(siz); + } + FA4_SET(FA4_OWNER, bmvalp); + } + if (vap->va_gid != VNOVAL) { + int error; + char *name; + error = idmap_gid_to_name(vap->va_gid, &name, &siz); + if (error || name == NULL || siz == 0) { + /* XXX */ + siz = sizeof("nogroup") - 1; + tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, + bpos); + *tl++ = txdr_unsigned(siz); + bcopy("nogroup", tl, siz); + len += NFSX_UNSIGNED + nfsm_rndup(siz); + } else { + tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, + bpos); + *tl++ = txdr_unsigned(siz); + bcopy(name, tl, siz); + len += NFSX_UNSIGNED + nfsm_rndup(siz); + } + FA4_SET(FA4_OWNER_GROUP, bmvalp); + } + if (vap->va_atime.tv_sec != VNOVAL) { + uint64_t val = vap->va_atime.tv_sec; + tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos); + FA4_SET(FA4_TIME_ACCESS_SET, bmvalp); + *tl++ = txdr_unsigned(THCLIENTTIME); + txdr_hyper(val, tl); tl += 2; + *tl++ = txdr_unsigned(vap->va_atime.tv_nsec); + len += 4 * NFSX_UNSIGNED; + } + if (vap->va_mtime.tv_sec != VNOVAL) { + uint64_t val = vap->va_mtime.tv_sec; + tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos); + FA4_SET(FA4_TIME_MODIFY_SET, bmvalp); + *tl++ = txdr_unsigned(THCLIENTTIME); + txdr_hyper(val, tl); tl += 2; + *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec); + len += 4 * NFSX_UNSIGNED; + } + + bmvalp[0] = txdr_unsigned(bmvalp[0]); + bmvalp[1] = txdr_unsigned(bmvalp[1]); + + *attrlenp = txdr_unsigned(len); + + return (0); +} + +int +nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos) +{ + uint32_t taglen, t1, *tl; + + tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); + if (tl == NULL) + return (EBADRPC); + + /* Reply status is handled by the RPC code */ + + taglen = fxdr_unsigned(uint32_t, *tl++); + t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos); + if (t1 != 0) + return (EBADRPC); + + tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); + if (tl == NULL) + return (EBADRPC); + + cp->rep_nops = fxdr_unsigned(uint32_t, *tl++); + + return (0); +} + +int +nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op, + uint32_t skipbytes, struct mbuf **md, caddr_t *dpos) +{ + uint32_t t1, dop, status; + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status); + if (t1 != 0) + return (t1); + + if (dop != op || status != 0) + return (EBADRPC); + + if (skipbytes > 0) + NFSM_ADV(nfsm_rndup(skipbytes)); + + return (0); +} + +int +nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl; + + tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR || + *tl++ != 0) + return (EBADRPC); + + return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos)); +} + +int +nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos) +{ + uint32_t t1, op, bmlen, status; + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); + if (t1 != 0) + return (t1); + + if (op != NFSV4OP_SETATTR || status != 0) + return (EBADRPC); + + t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen); + if (t1 != 0) + return (t1); + + return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2)); +} + +int +nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl, len, xdrlen; + + tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH) + return (EBADRPC); + + if (*tl++ != 0) + return (EBADRPC); + + NFSM_DISSECT(NFSX_UNSIGNED); + len = fxdr_unsigned(uint32_t, *tl++); + if (len > NFSX_V4FH) + return (EBADRPC); + + /* XXX integrate this into nfs_mtofh()? */ + + gfh->fh_len = len; + xdrlen = nfsm_rndup(len); + + NFSM_DISSECT(xdrlen); + bcopy(tl, &gfh->fh_val, xdrlen); + + return (0); +} + +int +nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp, + struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl; + + tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID) + return (EBADRPC); + + /* Handle NFS4ERR_CLID_INUSE specially */ + if (*tl++ != 0) + return (EBADRPC); + + NFSM_DISSECT(2 * NFSX_UNSIGNED); + sci->clientid = fxdr_hyper(tl); + + NFSM_DISSECT(nfsm_rndup(NFSX_V4VERF)); + bcopy(tl, sci->verf, NFSX_V4VERF); + + return (0); +} + +int +nfsm_v4dissect_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl, t1; + + tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_CLOSE || + *tl++ != 0) + return (EBADRPC); + + /* Copy stateid */ + t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid); + if (t1 != 0) + return (t1); + + return (0); +} + +int +nfsm_v4dissect_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl; + + tl = nfsm_dissect_xx(4 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_ACCESS || + *tl++ != 0) + return (EBADRPC); + + acc->supported = fxdr_unsigned(uint32_t, *tl++); + acc->rmode = fxdr_unsigned(uint32_t, *tl++); + + return (0); +} + +int +nfsm_v4dissect_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl, t1, bmlen, delegtype = ODNONE; + int error = 0; + nfsv4changeinfo cinfo; + struct nfs4_fctx *fcp = op->fcp; + + tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN || + *tl++ != 0) + return (EBADRPC); + + t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid); + if (t1 != 0) + return (t1); + + error = nfsm_v4dissect_changeinfo_xx(&cinfo, md, dpos); + if (error != 0) + goto nfsmout; + + NFSM_DISSECT(2 * NFSX_UNSIGNED); + + op->rflags = fxdr_unsigned(uint32_t, *tl++); + bmlen = fxdr_unsigned(uint32_t, *tl++); + if (bmlen > 2) { + error = EBADRPC; + goto nfsmout; + } + + /* Skip */ + NFSM_ADV(nfsm_rndup(bmlen << 2)); + + NFSM_DISSECT(NFSX_UNSIGNED); + delegtype = fxdr_unsigned(uint32_t, *tl++); + switch (delegtype) { + case ODREAD: + case ODWRITE: + printf("nfs4: client delegation not yet supported\n"); + error = EOPNOTSUPP; + goto nfsmout; + break; + case ODNONE: + default: + break; + } + + nfsmout: + return (error); +} + +int +nfsm_v4dissect_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl; + + tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); + if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN_CONFIRM || + *tl++ != 0) + return (EBADRPC); + + return nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, op->fcp->stateid); +} + +int +nfsm_v4dissect_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t op, status, t1; + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); + if (t1 != 0) + return (t1); + + if (op != NFSV4OP_READ || status != 0) + return (EBADRPC); + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &r->eof, &r->retlen); + if (t1 != 0) + return (t1); + + return (nfsm_mbuftouio(md, r->uiop, r->retlen, dpos)); +} + +int +nfsm_v4dissect_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t op, status, t1; + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); + if (t1 != 0) + return (t1); + + if (op != NFSV4OP_WRITE || status != 0) + return (EBADRPC); + + return (nfsm_dissectf_xx(md, dpos, "uuo", &w->retlen, &w->committed, + NFSX_V4VERF, w->wverf)); +} + +int +nfsm_v4dissect_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t t1, op, status; + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); + if (t1 != 0) + return (t1); + + if (op != NFSV4OP_COMMIT || status != 0) + return (EBADRPC); + + return (nfsm_dissectf_xx(md, dpos, "o", NFSX_V4VERF, c->verf)); +} + +int +nfsm_v4dissect_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t t1, *tl, op, status, bmlen; + nfsv4changeinfo ci; + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); + if (t1 != 0) + return (t1); + + if (op != NFSV4OP_CREATE || status != 0) + return (EBADRPC); + + /* Just throw this away for now */ + t1 = nfsm_v4dissect_changeinfo_xx(&ci, md, dpos); + if (t1 != 0) + return (t1); + + /* Throw this away too */ + NFSM_DISSECT(NFSX_UNSIGNED); + bmlen = fxdr_unsigned(uint32_t, *tl++); + NFSM_DISSECT(bmlen * NFSX_UNSIGNED); + tl += bmlen; + + return 0; +} + +int +nfsm_v4dissect_readlink_xx(struct nfs4_compound *cp, struct uio *uiop, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t t1, *tl, op, status, linklen; + + t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); + if (t1 != 0) + return (t1); + + if (op != NFSV4OP_READLINK || status != 0) + return (EBADRPC); + + /* Do this one manually for careful checking of sizes. */ + NFSM_DISSECT(NFSX_UNSIGNED); + linklen = fxdr_unsigned(uint32_t, *tl++); + if (linklen <= 0) + return (EBADRPC); + + return (nfsm_mbuftouio(md, uiop, MIN(linklen, uiop->uio_resid), dpos)); +} + +int +nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *ci, + struct mbuf **md, caddr_t *dpos) +{ + uint32_t *tl; + + NFSM_DISSECT(5 * NFSX_UNSIGNED); + + ci->ciatomic = fxdr_unsigned(uint32_t, *tl++); + ci->cibefore = fxdr_hyper(tl); tl += 2; + ci->ciafter = fxdr_hyper(tl); tl += 2; + + return (0); +} + +int +nfsm_v4dissect_attrs_xx(struct nfsv4_fattr *fa, struct mbuf **md, caddr_t *dpos) +{ + uint32_t t1, *tl, bmlen, bmval[2], attrlen, len = 0; + + /* Bitmap length + value */ + NFSM_DISSECT(NFSX_UNSIGNED); + + bmlen = fxdr_unsigned(uint32_t, *tl++); + if (bmlen > 2) + return (EBADRPC); + + if (bmlen == 0) + return (0); + + NFSM_DISSECT(nfsm_rndup(bmlen << 2) + NFSX_UNSIGNED); + + bmval[0] = bmlen > 0 ? fxdr_unsigned(uint32_t, *tl++) : 0; + bmval[1] = bmlen > 1 ? fxdr_unsigned(uint32_t, *tl++) : 0; + + /* Attribute length */ + attrlen = fxdr_unsigned(uint32_t, *tl++); + + /* + * XXX check for correct (<=) attributes mask return from + * server. need to pass this in. + */ + + if (FA4_ISSET(FA4_TYPE, bmval)) { + /* overflow check */ + NFSM_DISSECT(NFSX_UNSIGNED); + fa->fa4_type = fxdr_unsigned(uint32_t, *tl++); + fa->fa4_valid |= FA4V_TYPE; + len += NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_CHANGE, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_changeid = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_CHANGEID; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_SIZE, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_size = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_SIZE; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_FSID, bmval)) { + NFSM_DISSECT(4 * NFSX_UNSIGNED); + fa->fa4_fsid_major = fxdr_hyper(tl); tl += 2; + fa->fa4_fsid_minor = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_SIZE; + len += 4 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_LEASE_TIME, bmval)) { + NFSM_DISSECT(NFSX_UNSIGNED); + fa->fa4_lease_time = fxdr_unsigned(uint32_t, *tl++); + fa->fa4_valid |= FA4V_LEASE_TIME; + len += NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_FILEID, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_fileid = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_FILEID; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_FILES_FREE, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_ffree = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_FFREE; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_FILES_TOTAL, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_ftotal = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_FTOTAL; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_MAXFILESIZE, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_maxfilesize = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_MAXFILESIZE; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_MAXNAME, bmval)) { + NFSM_DISSECT(NFSX_UNSIGNED); + fa->fa4_maxname = fxdr_unsigned(uint32_t, *tl++); + fa->fa4_valid |= FA4V_MAXNAME; + len += NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_MAXREAD, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_maxread = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_MAXREAD; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_MAXWRITE, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_maxwrite = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_MAXWRITE; + len += 2 * NFSX_UNSIGNED; + } + + if (FA4_ISSET(FA4_MODE, bmval)) { + NFSM_DISSECT(NFSX_UNSIGNED); + fa->fa4_mode = fxdr_unsigned(mode_t, *tl++); + fa->fa4_valid |= FA4V_MODE; + len += NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_NUMLINKS, bmval)) { + NFSM_DISSECT(NFSX_UNSIGNED); + fa->fa4_nlink = fxdr_unsigned(nlink_t, *tl++); + fa->fa4_valid |= FA4V_NLINK; + len += NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_OWNER, bmval)) { + uint32_t ownerlen; + int error; + + NFSM_DISSECT(NFSX_UNSIGNED); + + ownerlen = fxdr_unsigned(uint32_t, *tl++); + NFSM_DISSECT(nfsm_rndup(ownerlen)); + error = idmap_name_to_uid((char *)tl, ownerlen, &fa->fa4_uid); + if (error) + fa->fa4_uid = -2; + fa->fa4_valid |= FA4V_UID; + len += NFSX_UNSIGNED + nfsm_rndup(ownerlen); + } + if (FA4_ISSET(FA4_OWNER_GROUP, bmval)) { + uint32_t ownergrouplen; + int error; + + NFSM_DISSECT(NFSX_UNSIGNED); + ownergrouplen = fxdr_unsigned(uint32_t, *tl++); + NFSM_DISSECT(nfsm_rndup(ownergrouplen)); + error = idmap_name_to_gid((char *)tl, ownergrouplen, &fa->fa4_gid); + if (error) + fa->fa4_gid = -2; + fa->fa4_valid |= FA4V_GID; + len += NFSX_UNSIGNED + nfsm_rndup(ownergrouplen); + } + if (FA4_ISSET(FA4_RAWDEV, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_rdev_major = fxdr_unsigned(uint32_t, *tl++); + fa->fa4_rdev_minor = fxdr_unsigned(uint32_t, *tl++); + fa->fa4_valid |= FA4V_RDEV; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_SPACE_AVAIL, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_savail = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_SAVAIL; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_SPACE_FREE, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_sfree = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_SFREE; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_SPACE_TOTAL, bmval)) { + NFSM_DISSECT(2 * NFSX_UNSIGNED); + fa->fa4_stotal = fxdr_hyper(tl); + fa->fa4_valid |= FA4V_STOTAL; + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_SPACE_USED, bmval)) { + NFSM_ADV(2 * NFSX_UNSIGNED); + len += 2 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_TIME_ACCESS, bmval)) { + NFSM_MTOTIME(fa->fa4_atime); + fa->fa4_valid |= FA4V_ATIME; + len += 3 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_TIME_CREATE, bmval)) { + NFSM_MTOTIME(fa->fa4_ctime); + fa->fa4_valid |= FA4V_CTIME; + len += 3 * NFSX_UNSIGNED; + } + if (FA4_ISSET(FA4_TIME_MODIFY, bmval)) { + NFSM_MTOTIME(fa->fa4_mtime); + fa->fa4_valid |= FA4V_MTIME; + len += 3 * NFSX_UNSIGNED; + } + + if (len != attrlen) + return (EBADRPC); + + return (0); +} |