138420Smckusick /* 2*63485Sbostic * Copyright (c) 1989, 1993 3*63485Sbostic * The Regents of the University of California. All rights reserved. 438420Smckusick * 538420Smckusick * This code is derived from software contributed to Berkeley by 638420Smckusick * Rick Macklem at The University of Guelph. 738420Smckusick * 844513Sbostic * %sccs.include.redist.c% 938420Smckusick * 10*63485Sbostic * @(#)nfs_subs.c 8.1 (Berkeley) 06/16/93 1138420Smckusick */ 1238420Smckusick 1338420Smckusick /* 1438420Smckusick * These functions support the macros and help fiddle mbuf chains for 1538420Smckusick * the nfs op functions. They do things like create the rpc header and 1638420Smckusick * copy data between mbuf chains and uio lists. 1738420Smckusick */ 1853322Smckusick #include <sys/param.h> 1953322Smckusick #include <sys/proc.h> 2053322Smckusick #include <sys/systm.h> 2153322Smckusick #include <sys/kernel.h> 2253322Smckusick #include <sys/mount.h> 2353322Smckusick #include <sys/vnode.h> 2453322Smckusick #include <sys/namei.h> 2553322Smckusick #include <sys/mbuf.h> 2653322Smckusick #include <sys/socket.h> 2754445Smckusick #include <sys/stat.h> 2847573Skarels 2953322Smckusick #include <nfs/rpcv2.h> 3053322Smckusick #include <nfs/nfsv2.h> 3153322Smckusick #include <nfs/nfsnode.h> 3253322Smckusick #include <nfs/nfs.h> 3353322Smckusick #include <nfs/xdr_subs.h> 3453322Smckusick #include <nfs/nfsm_subs.h> 3553322Smckusick #include <nfs/nfsmount.h> 3653322Smckusick #include <nfs/nqnfs.h> 3753322Smckusick #include <nfs/nfsrtt.h> 3853322Smckusick 3955703Smckusick #include <miscfs/specfs/specdev.h> 4055703Smckusick 4154988Smckusick #include <netinet/in.h> 4254988Smckusick #ifdef ISO 4354988Smckusick #include <netiso/iso.h> 4454988Smckusick #endif 4554988Smckusick 4638420Smckusick #define TRUE 1 4738420Smckusick #define FALSE 0 4838420Smckusick 4938420Smckusick /* 5038420Smckusick * Data items converted to xdr at startup, since they are constant 5138420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 5238420Smckusick */ 5338420Smckusick u_long nfs_procids[NFS_NPROCS]; 5438420Smckusick u_long nfs_xdrneg1; 5552196Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 5652196Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 5752196Smckusick rpc_auth_kerb; 5838420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 5952196Smckusick 6038420Smckusick /* And other global data */ 6152196Smckusick static u_long nfs_xid = 0; 6242244Smckusick enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 6341902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 6456470Smckusick extern struct queue_entry nfs_bufq; 6541902Smckusick extern struct nfsreq nfsreqh; 6652196Smckusick extern int nqnfs_piggy[NFS_NPROCS]; 6752196Smckusick extern struct nfsrtt nfsrtt; 6852196Smckusick extern time_t nqnfsstarttime; 6952196Smckusick extern u_long nqnfs_prog, nqnfs_vers; 7052196Smckusick extern int nqsrv_clockskew; 7152196Smckusick extern int nqsrv_writeslack; 7252196Smckusick extern int nqsrv_maxlease; 7338420Smckusick 7438420Smckusick /* 7538420Smckusick * Create the header for an rpc request packet 7638420Smckusick * The hsiz is the size of the rest of the nfs request header. 7738420Smckusick * (just used to decide if a cluster is a good idea) 7838420Smckusick */ 7952196Smckusick struct mbuf * 8052196Smckusick nfsm_reqh(vp, procid, hsiz, bposp) 8152196Smckusick struct vnode *vp; 8239494Smckusick u_long procid; 8338420Smckusick int hsiz; 8452196Smckusick caddr_t *bposp; 8538420Smckusick { 8652196Smckusick register struct mbuf *mb; 8748049Smckusick register u_long *tl; 8852196Smckusick register caddr_t bpos; 8952196Smckusick struct mbuf *mb2; 9052196Smckusick struct nfsmount *nmp; 9152196Smckusick int nqflag; 9238420Smckusick 9352196Smckusick MGET(mb, M_WAIT, MT_DATA); 9452196Smckusick if (hsiz >= MINCLSIZE) 9552196Smckusick MCLGET(mb, M_WAIT); 9652196Smckusick mb->m_len = 0; 9752196Smckusick bpos = mtod(mb, caddr_t); 9852196Smckusick 9952196Smckusick /* 10052196Smckusick * For NQNFS, add lease request. 10152196Smckusick */ 10252196Smckusick if (vp) { 10352196Smckusick nmp = VFSTONFS(vp->v_mount); 10452196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 10552196Smckusick nqflag = NQNFS_NEEDLEASE(vp, procid); 10652196Smckusick if (nqflag) { 10752196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 10852196Smckusick *tl++ = txdr_unsigned(nqflag); 10952196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 11052196Smckusick } else { 11152196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 11252196Smckusick *tl = 0; 11352196Smckusick } 11452196Smckusick } 11552196Smckusick } 11652196Smckusick /* Finally, return values */ 11752196Smckusick *bposp = bpos; 11852196Smckusick return (mb); 11952196Smckusick } 12038420Smckusick 12152196Smckusick /* 12252196Smckusick * Build the RPC header and fill in the authorization info. 12352196Smckusick * The authorization string argument is only used when the credentials 12452196Smckusick * come from outside of the kernel. 12552196Smckusick * Returns the head of the mbuf list. 12652196Smckusick */ 12752196Smckusick struct mbuf * 12852196Smckusick nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 12952196Smckusick mrest_len, mbp, xidp) 13052196Smckusick register struct ucred *cr; 13152196Smckusick int nqnfs; 13252196Smckusick int procid; 13352196Smckusick int auth_type; 13452196Smckusick int auth_len; 13552196Smckusick char *auth_str; 13652196Smckusick struct mbuf *mrest; 13752196Smckusick int mrest_len; 13852196Smckusick struct mbuf **mbp; 13952196Smckusick u_long *xidp; 14052196Smckusick { 14152196Smckusick register struct mbuf *mb; 14252196Smckusick register u_long *tl; 14352196Smckusick register caddr_t bpos; 14452196Smckusick register int i; 14552196Smckusick struct mbuf *mreq, *mb2; 14652196Smckusick int siz, grpsiz, authsiz; 14752196Smckusick 14852196Smckusick authsiz = nfsm_rndup(auth_len); 14952196Smckusick if (auth_type == RPCAUTH_NQNFS) 15052196Smckusick authsiz += 2 * NFSX_UNSIGNED; 15152196Smckusick MGETHDR(mb, M_WAIT, MT_DATA); 15252196Smckusick if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 15352196Smckusick MCLGET(mb, M_WAIT); 15452196Smckusick } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 15552196Smckusick MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 15652196Smckusick } else { 15752196Smckusick MH_ALIGN(mb, 8*NFSX_UNSIGNED); 15852196Smckusick } 15952196Smckusick mb->m_len = 0; 16052196Smckusick mreq = mb; 16152196Smckusick bpos = mtod(mb, caddr_t); 16252196Smckusick 16338420Smckusick /* 16452196Smckusick * First the RPC header. 16538420Smckusick */ 16652196Smckusick nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 16752196Smckusick if (++nfs_xid == 0) 16852196Smckusick nfs_xid++; 16952196Smckusick *tl++ = *xidp = txdr_unsigned(nfs_xid); 17048049Smckusick *tl++ = rpc_call; 17148049Smckusick *tl++ = rpc_vers; 17252196Smckusick if (nqnfs) { 17352196Smckusick *tl++ = txdr_unsigned(NQNFS_PROG); 17452196Smckusick *tl++ = txdr_unsigned(NQNFS_VER1); 17552196Smckusick } else { 17652196Smckusick *tl++ = txdr_unsigned(NFS_PROG); 17752196Smckusick *tl++ = txdr_unsigned(NFS_VER2); 17852196Smckusick } 17952196Smckusick *tl++ = txdr_unsigned(procid); 18038420Smckusick 18152196Smckusick /* 18252196Smckusick * And then the authorization cred. 18352196Smckusick */ 18452196Smckusick *tl++ = txdr_unsigned(auth_type); 18552196Smckusick *tl = txdr_unsigned(authsiz); 18652196Smckusick switch (auth_type) { 18752196Smckusick case RPCAUTH_UNIX: 18852196Smckusick nfsm_build(tl, u_long *, auth_len); 18952196Smckusick *tl++ = 0; /* stamp ?? */ 19052196Smckusick *tl++ = 0; /* NULL hostname */ 19152196Smckusick *tl++ = txdr_unsigned(cr->cr_uid); 19252196Smckusick *tl++ = txdr_unsigned(cr->cr_groups[0]); 19352196Smckusick grpsiz = (auth_len >> 2) - 5; 19452196Smckusick *tl++ = txdr_unsigned(grpsiz); 19552196Smckusick for (i = 1; i <= grpsiz; i++) 19652196Smckusick *tl++ = txdr_unsigned(cr->cr_groups[i]); 19752196Smckusick break; 19852196Smckusick case RPCAUTH_NQNFS: 19952196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 20052196Smckusick *tl++ = txdr_unsigned(cr->cr_uid); 20152196Smckusick *tl = txdr_unsigned(auth_len); 20252196Smckusick siz = auth_len; 20352196Smckusick while (siz > 0) { 20452196Smckusick if (M_TRAILINGSPACE(mb) == 0) { 20552196Smckusick MGET(mb2, M_WAIT, MT_DATA); 20652196Smckusick if (siz >= MINCLSIZE) 20752196Smckusick MCLGET(mb2, M_WAIT); 20852196Smckusick mb->m_next = mb2; 20952196Smckusick mb = mb2; 21052196Smckusick mb->m_len = 0; 21152196Smckusick bpos = mtod(mb, caddr_t); 21252196Smckusick } 21355057Spendry i = min(siz, M_TRAILINGSPACE(mb)); 21452196Smckusick bcopy(auth_str, bpos, i); 21552196Smckusick mb->m_len += i; 21652196Smckusick auth_str += i; 21752196Smckusick bpos += i; 21852196Smckusick siz -= i; 21938420Smckusick } 22057787Smckusick if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 22152196Smckusick for (i = 0; i < siz; i++) 22252196Smckusick *bpos++ = '\0'; 22352196Smckusick mb->m_len += siz; 22452196Smckusick } 22552196Smckusick break; 22652196Smckusick }; 22752196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 22852196Smckusick *tl++ = txdr_unsigned(RPCAUTH_NULL); 22952196Smckusick *tl = 0; 23052196Smckusick mb->m_next = mrest; 23152196Smckusick mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 23252196Smckusick mreq->m_pkthdr.rcvif = (struct ifnet *)0; 23352196Smckusick *mbp = mb; 23438420Smckusick return (mreq); 23538420Smckusick } 23638420Smckusick 23738420Smckusick /* 23838420Smckusick * copies mbuf chain to the uio scatter/gather list 23938420Smckusick */ 24038420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 24138420Smckusick struct mbuf **mrep; 24243353Smckusick register struct uio *uiop; 24338420Smckusick int siz; 24438420Smckusick caddr_t *dpos; 24538420Smckusick { 24643353Smckusick register char *mbufcp, *uiocp; 24738420Smckusick register int xfer, left, len; 24838420Smckusick register struct mbuf *mp; 24938420Smckusick long uiosiz, rem; 25041902Smckusick int error = 0; 25138420Smckusick 25238420Smckusick mp = *mrep; 25338420Smckusick mbufcp = *dpos; 25438420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 25538420Smckusick rem = nfsm_rndup(siz)-siz; 25638420Smckusick while (siz > 0) { 25738420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 25841902Smckusick return (EFBIG); 25938420Smckusick left = uiop->uio_iov->iov_len; 26038420Smckusick uiocp = uiop->uio_iov->iov_base; 26138420Smckusick if (left > siz) 26238420Smckusick left = siz; 26338420Smckusick uiosiz = left; 26438420Smckusick while (left > 0) { 26538420Smckusick while (len == 0) { 26638420Smckusick mp = mp->m_next; 26738420Smckusick if (mp == NULL) 26838420Smckusick return (EBADRPC); 26938420Smckusick mbufcp = mtod(mp, caddr_t); 27038420Smckusick len = mp->m_len; 27138420Smckusick } 27238420Smckusick xfer = (left > len) ? len : left; 27338420Smckusick #ifdef notdef 27438420Smckusick /* Not Yet.. */ 27538420Smckusick if (uiop->uio_iov->iov_op != NULL) 27638420Smckusick (*(uiop->uio_iov->iov_op)) 27738420Smckusick (mbufcp, uiocp, xfer); 27838420Smckusick else 27938420Smckusick #endif 28038420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 28138420Smckusick bcopy(mbufcp, uiocp, xfer); 28238420Smckusick else 28338420Smckusick copyout(mbufcp, uiocp, xfer); 28438420Smckusick left -= xfer; 28538420Smckusick len -= xfer; 28638420Smckusick mbufcp += xfer; 28738420Smckusick uiocp += xfer; 28839585Smckusick uiop->uio_offset += xfer; 28938420Smckusick uiop->uio_resid -= xfer; 29038420Smckusick } 29138420Smckusick if (uiop->uio_iov->iov_len <= siz) { 29238420Smckusick uiop->uio_iovcnt--; 29338420Smckusick uiop->uio_iov++; 29438420Smckusick } else { 29538420Smckusick uiop->uio_iov->iov_base += uiosiz; 29638420Smckusick uiop->uio_iov->iov_len -= uiosiz; 29738420Smckusick } 29838420Smckusick siz -= uiosiz; 29938420Smckusick } 30038420Smckusick *dpos = mbufcp; 30138420Smckusick *mrep = mp; 30241902Smckusick if (rem > 0) { 30341902Smckusick if (len < rem) 30441902Smckusick error = nfs_adv(mrep, dpos, rem, len); 30541902Smckusick else 30641902Smckusick *dpos += rem; 30741902Smckusick } 30841902Smckusick return (error); 30938420Smckusick } 31038420Smckusick 31138420Smckusick /* 31238420Smckusick * copies a uio scatter/gather list to an mbuf chain... 31338420Smckusick */ 31438420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 31538420Smckusick register struct uio *uiop; 31638420Smckusick struct mbuf **mq; 31738420Smckusick int siz; 31838420Smckusick caddr_t *bpos; 31938420Smckusick { 32043353Smckusick register char *uiocp; 32143353Smckusick register struct mbuf *mp, *mp2; 32252196Smckusick register int xfer, left, mlen; 32343353Smckusick int uiosiz, clflg, rem; 32443353Smckusick char *cp; 32538420Smckusick 32638420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 32738420Smckusick clflg = 1; 32838420Smckusick else 32938420Smckusick clflg = 0; 33038420Smckusick rem = nfsm_rndup(siz)-siz; 33152196Smckusick mp = mp2 = *mq; 33238420Smckusick while (siz > 0) { 33338420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 33441902Smckusick return (EINVAL); 33538420Smckusick left = uiop->uio_iov->iov_len; 33638420Smckusick uiocp = uiop->uio_iov->iov_base; 33738420Smckusick if (left > siz) 33838420Smckusick left = siz; 33938420Smckusick uiosiz = left; 34038420Smckusick while (left > 0) { 34152196Smckusick mlen = M_TRAILINGSPACE(mp); 34252196Smckusick if (mlen == 0) { 34352196Smckusick MGET(mp, M_WAIT, MT_DATA); 34452196Smckusick if (clflg) 34552196Smckusick MCLGET(mp, M_WAIT); 34652196Smckusick mp->m_len = 0; 34752196Smckusick mp2->m_next = mp; 34852196Smckusick mp2 = mp; 34952196Smckusick mlen = M_TRAILINGSPACE(mp); 35052196Smckusick } 35152196Smckusick xfer = (left > mlen) ? mlen : left; 35238420Smckusick #ifdef notdef 35338420Smckusick /* Not Yet.. */ 35438420Smckusick if (uiop->uio_iov->iov_op != NULL) 35538420Smckusick (*(uiop->uio_iov->iov_op)) 35652196Smckusick (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 35738420Smckusick else 35838420Smckusick #endif 35938420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 36052196Smckusick bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 36138420Smckusick else 36252196Smckusick copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 36352196Smckusick mp->m_len += xfer; 36438420Smckusick left -= xfer; 36538420Smckusick uiocp += xfer; 36639585Smckusick uiop->uio_offset += xfer; 36738420Smckusick uiop->uio_resid -= xfer; 36838420Smckusick } 36938420Smckusick if (uiop->uio_iov->iov_len <= siz) { 37038420Smckusick uiop->uio_iovcnt--; 37138420Smckusick uiop->uio_iov++; 37238420Smckusick } else { 37338420Smckusick uiop->uio_iov->iov_base += uiosiz; 37438420Smckusick uiop->uio_iov->iov_len -= uiosiz; 37538420Smckusick } 37638420Smckusick siz -= uiosiz; 37738420Smckusick } 37838420Smckusick if (rem > 0) { 37952196Smckusick if (rem > M_TRAILINGSPACE(mp)) { 38038420Smckusick MGET(mp, M_WAIT, MT_DATA); 38138420Smckusick mp->m_len = 0; 38238420Smckusick mp2->m_next = mp; 38338420Smckusick } 38438420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 38538420Smckusick for (left = 0; left < rem; left++) 38638420Smckusick *cp++ = '\0'; 38738420Smckusick mp->m_len += rem; 38838420Smckusick *bpos = cp; 38938420Smckusick } else 39038420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 39138420Smckusick *mq = mp; 39241902Smckusick return (0); 39338420Smckusick } 39438420Smckusick 39538420Smckusick /* 39638420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 39738420Smckusick * pointed to by returned val. 39852196Smckusick * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 39938420Smckusick * cases. (The macros use the vars. dpos and dpos2) 40038420Smckusick */ 40163482Smckusick nfsm_disct(mdp, dposp, siz, left, cp2) 40238420Smckusick struct mbuf **mdp; 40338420Smckusick caddr_t *dposp; 40438420Smckusick int siz; 40538420Smckusick int left; 40638420Smckusick caddr_t *cp2; 40738420Smckusick { 40838420Smckusick register struct mbuf *mp, *mp2; 40938420Smckusick register int siz2, xfer; 41052196Smckusick register caddr_t p; 41138420Smckusick 41238420Smckusick mp = *mdp; 41338420Smckusick while (left == 0) { 41438420Smckusick *mdp = mp = mp->m_next; 41538420Smckusick if (mp == NULL) 41641902Smckusick return (EBADRPC); 41738420Smckusick left = mp->m_len; 41838420Smckusick *dposp = mtod(mp, caddr_t); 41938420Smckusick } 42038420Smckusick if (left >= siz) { 42138420Smckusick *cp2 = *dposp; 42238420Smckusick *dposp += siz; 42338420Smckusick } else if (mp->m_next == NULL) { 42441902Smckusick return (EBADRPC); 42541902Smckusick } else if (siz > MHLEN) { 42638420Smckusick panic("nfs S too big"); 42738420Smckusick } else { 42863482Smckusick MGET(mp2, M_WAIT, MT_DATA); 42963482Smckusick mp2->m_next = mp->m_next; 43063482Smckusick mp->m_next = mp2; 43163482Smckusick mp->m_len -= left; 43263482Smckusick mp = mp2; 43352196Smckusick *cp2 = p = mtod(mp, caddr_t); 43452196Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 43538420Smckusick siz2 = siz-left; 43652196Smckusick p += left; 43738420Smckusick mp2 = mp->m_next; 43841902Smckusick /* Loop around copying up the siz2 bytes */ 43938420Smckusick while (siz2 > 0) { 44038420Smckusick if (mp2 == NULL) 44138420Smckusick return (EBADRPC); 44238420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 44341902Smckusick if (xfer > 0) { 44452196Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 44541902Smckusick NFSMADV(mp2, xfer); 44641902Smckusick mp2->m_len -= xfer; 44752196Smckusick p += xfer; 44841902Smckusick siz2 -= xfer; 44941902Smckusick } 45038420Smckusick if (siz2 > 0) 45138420Smckusick mp2 = mp2->m_next; 45238420Smckusick } 45338420Smckusick mp->m_len = siz; 45438420Smckusick *mdp = mp2; 45538420Smckusick *dposp = mtod(mp2, caddr_t); 45638420Smckusick } 45739494Smckusick return (0); 45838420Smckusick } 45938420Smckusick 46038420Smckusick /* 46141902Smckusick * Advance the position in the mbuf chain. 46238420Smckusick */ 46338420Smckusick nfs_adv(mdp, dposp, offs, left) 46438420Smckusick struct mbuf **mdp; 46538420Smckusick caddr_t *dposp; 46638420Smckusick int offs; 46738420Smckusick int left; 46838420Smckusick { 46938420Smckusick register struct mbuf *m; 47038420Smckusick register int s; 47138420Smckusick 47238420Smckusick m = *mdp; 47338420Smckusick s = left; 47438420Smckusick while (s < offs) { 47538420Smckusick offs -= s; 47638420Smckusick m = m->m_next; 47738420Smckusick if (m == NULL) 47841902Smckusick return (EBADRPC); 47938420Smckusick s = m->m_len; 48038420Smckusick } 48138420Smckusick *mdp = m; 48238420Smckusick *dposp = mtod(m, caddr_t)+offs; 48341902Smckusick return (0); 48438420Smckusick } 48538420Smckusick 48638420Smckusick /* 48738420Smckusick * Copy a string into mbufs for the hard cases... 48838420Smckusick */ 48938420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 49038420Smckusick struct mbuf **mb; 49138420Smckusick char **bpos; 49238420Smckusick char *cp; 49338420Smckusick long siz; 49438420Smckusick { 49538420Smckusick register struct mbuf *m1, *m2; 49638420Smckusick long left, xfer, len, tlen; 49748049Smckusick u_long *tl; 49838420Smckusick int putsize; 49938420Smckusick 50038420Smckusick putsize = 1; 50138420Smckusick m2 = *mb; 50252196Smckusick left = M_TRAILINGSPACE(m2); 50338420Smckusick if (left > 0) { 50448049Smckusick tl = ((u_long *)(*bpos)); 50548049Smckusick *tl++ = txdr_unsigned(siz); 50638420Smckusick putsize = 0; 50738420Smckusick left -= NFSX_UNSIGNED; 50838420Smckusick m2->m_len += NFSX_UNSIGNED; 50938420Smckusick if (left > 0) { 51048049Smckusick bcopy(cp, (caddr_t) tl, left); 51138420Smckusick siz -= left; 51238420Smckusick cp += left; 51338420Smckusick m2->m_len += left; 51438420Smckusick left = 0; 51538420Smckusick } 51638420Smckusick } 51752196Smckusick /* Loop around adding mbufs */ 51838420Smckusick while (siz > 0) { 51938420Smckusick MGET(m1, M_WAIT, MT_DATA); 52038420Smckusick if (siz > MLEN) 52141902Smckusick MCLGET(m1, M_WAIT); 52238420Smckusick m1->m_len = NFSMSIZ(m1); 52338420Smckusick m2->m_next = m1; 52438420Smckusick m2 = m1; 52548049Smckusick tl = mtod(m1, u_long *); 52638420Smckusick tlen = 0; 52738420Smckusick if (putsize) { 52848049Smckusick *tl++ = txdr_unsigned(siz); 52938420Smckusick m1->m_len -= NFSX_UNSIGNED; 53038420Smckusick tlen = NFSX_UNSIGNED; 53138420Smckusick putsize = 0; 53238420Smckusick } 53338420Smckusick if (siz < m1->m_len) { 53438420Smckusick len = nfsm_rndup(siz); 53538420Smckusick xfer = siz; 53638420Smckusick if (xfer < len) 53748049Smckusick *(tl+(xfer>>2)) = 0; 53838420Smckusick } else { 53938420Smckusick xfer = len = m1->m_len; 54038420Smckusick } 54148049Smckusick bcopy(cp, (caddr_t) tl, xfer); 54238420Smckusick m1->m_len = len+tlen; 54338420Smckusick siz -= xfer; 54438420Smckusick cp += xfer; 54538420Smckusick } 54638420Smckusick *mb = m1; 54738420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 54841902Smckusick return (0); 54938420Smckusick } 55038420Smckusick 55138420Smckusick /* 55238420Smckusick * Called once to initialize data structures... 55338420Smckusick */ 55439444Smckusick nfs_init() 55538420Smckusick { 55638420Smckusick register int i; 55752196Smckusick union nqsrvthead *lhp; 55838420Smckusick 55952196Smckusick nfsrtt.pos = 0; 56038420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 56138420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 56238420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 56338420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 56438420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 56538420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 56652196Smckusick rpc_autherr = txdr_unsigned(RPC_AUTHERR); 56752196Smckusick rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 56838420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 56952196Smckusick rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 57038420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 57138420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 57238420Smckusick nfs_true = txdr_unsigned(TRUE); 57338420Smckusick nfs_false = txdr_unsigned(FALSE); 57438420Smckusick /* Loop thru nfs procids */ 57538420Smckusick for (i = 0; i < NFS_NPROCS; i++) 57638420Smckusick nfs_procids[i] = txdr_unsigned(i); 57739345Smckusick /* Ensure async daemons disabled */ 57841902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 57939345Smckusick nfs_iodwant[i] = (struct proc *)0; 58056470Smckusick queue_init(&nfs_bufq); 58138420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 58238420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 58352979Smckusick nfsrv_init(0); /* Init server data structures */ 58439755Smckusick nfsrv_initcache(); /* Init the server request cache */ 58541902Smckusick 58641902Smckusick /* 58752196Smckusick * Initialize the nqnfs server stuff. 58852196Smckusick */ 58952196Smckusick if (nqnfsstarttime == 0) { 59052196Smckusick nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 59152196Smckusick + nqsrv_clockskew + nqsrv_writeslack; 59252196Smckusick NQLOADNOVRAM(nqnfsstarttime); 59352196Smckusick nqnfs_prog = txdr_unsigned(NQNFS_PROG); 59452196Smckusick nqnfs_vers = txdr_unsigned(NQNFS_VER1); 59552196Smckusick nqthead.th_head[0] = &nqthead; 59652196Smckusick nqthead.th_head[1] = &nqthead; 59755519Smckusick nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash); 59852196Smckusick } 59952196Smckusick 60052196Smckusick /* 60141902Smckusick * Initialize reply list and start timer 60241902Smckusick */ 60341902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 60438420Smckusick nfs_timer(); 60538420Smckusick } 60638420Smckusick 60738420Smckusick /* 60838420Smckusick * Attribute cache routines. 60938420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 61038420Smckusick * that are on the mbuf list 61138420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 61238420Smckusick * error otherwise 61338420Smckusick */ 61438420Smckusick 61538420Smckusick /* 61639444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 61738420Smckusick * the values on the mbuf list and 61838420Smckusick * Iff vap not NULL 61938420Smckusick * copy the attributes to *vaper 62038420Smckusick */ 62139457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 62239457Smckusick struct vnode **vpp; 62338420Smckusick struct mbuf **mdp; 62438420Smckusick caddr_t *dposp; 62538420Smckusick struct vattr *vaper; 62638420Smckusick { 62739457Smckusick register struct vnode *vp = *vpp; 62838420Smckusick register struct vattr *vap; 62938884Smacklem register struct nfsv2_fattr *fp; 63053553Sheideman extern int (**spec_nfsv2nodeop_p)(); 63155519Smckusick register struct nfsnode *np, *nq, **nhpp; 63239494Smckusick register long t1; 63339494Smckusick caddr_t dpos, cp2; 63456287Smckusick int error = 0, isnq; 63539494Smckusick struct mbuf *md; 63652196Smckusick enum vtype vtyp; 63752196Smckusick u_short vmode; 63842244Smckusick long rdev; 63956287Smckusick struct timespec mtime; 64039444Smckusick struct vnode *nvp; 64138420Smckusick 64238420Smckusick md = *mdp; 64338420Smckusick dpos = *dposp; 64452196Smckusick t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 64556287Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 64663482Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2)) 64738420Smckusick return (error); 64838884Smacklem fp = (struct nfsv2_fattr *)cp2; 64952196Smckusick vtyp = nfstov_type(fp->fa_type); 65052196Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode); 65153384Smckusick if (vtyp == VNON || vtyp == VREG) 65252196Smckusick vtyp = IFTOVT(vmode); 65356287Smckusick if (isnq) { 65456287Smckusick rdev = fxdr_unsigned(long, fp->fa_nqrdev); 65556287Smckusick fxdr_nqtime(&fp->fa_nqmtime, &mtime); 65656287Smckusick } else { 65756287Smckusick rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 65856287Smckusick fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 65956287Smckusick } 66039444Smckusick /* 66139444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 66239444Smckusick * n_mtime fields. Check to see if it represents a special 66339444Smckusick * device, and if so, check for a possible alias. Once the 66439444Smckusick * correct vnode has been obtained, fill in the rest of the 66539444Smckusick * information. 66639444Smckusick */ 66738420Smckusick np = VTONFS(vp); 66839444Smckusick if (vp->v_type == VNON) { 66952196Smckusick if (vtyp == VCHR && rdev == 0xffffffff) 67052196Smckusick vp->v_type = vtyp = VFIFO; 67142244Smckusick else 67252196Smckusick vp->v_type = vtyp; 67340295Smckusick if (vp->v_type == VFIFO) { 67440295Smckusick #ifdef FIFO 67553553Sheideman extern int (**fifo_nfsv2nodeop_p)(); 67653553Sheideman vp->v_op = fifo_nfsv2nodeop_p; 67740295Smckusick #else 67840295Smckusick return (EOPNOTSUPP); 67940295Smckusick #endif /* FIFO */ 68040295Smckusick } 68139444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 68253553Sheideman vp->v_op = spec_nfsv2nodeop_p; 68342244Smckusick if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 68439444Smckusick /* 68551984Smckusick * Discard unneeded vnode, but save its nfsnode. 68651984Smckusick */ 68755519Smckusick if (nq = np->n_forw) 68855519Smckusick nq->n_back = np->n_back; 68955519Smckusick *np->n_back = nq; 69051984Smckusick nvp->v_data = vp->v_data; 69151984Smckusick vp->v_data = NULL; 69253553Sheideman vp->v_op = spec_vnodeop_p; 69351984Smckusick vrele(vp); 69451984Smckusick vgone(vp); 69551984Smckusick /* 69639444Smckusick * Reinitialize aliased node. 69739444Smckusick */ 69839444Smckusick np->n_vnode = nvp; 69955519Smckusick nhpp = (struct nfsnode **)nfs_hash(&np->n_fh); 70055519Smckusick if (nq = *nhpp) 70155519Smckusick nq->n_back = &np->n_forw; 70255519Smckusick np->n_forw = nq; 70355519Smckusick np->n_back = nhpp; 70455519Smckusick *nhpp = np; 70551984Smckusick *vpp = vp = nvp; 70639444Smckusick } 70739444Smckusick } 70856287Smckusick np->n_mtime = mtime.ts_sec; 70939444Smckusick } 71038420Smckusick vap = &np->n_vattr; 71152196Smckusick vap->va_type = vtyp; 71252196Smckusick vap->va_mode = (vmode & 07777); 71338884Smacklem vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 71438884Smacklem vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 71538884Smacklem vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 71656287Smckusick vap->va_rdev = (dev_t)rdev; 71756287Smckusick vap->va_mtime = mtime; 71856287Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 71956287Smckusick if (isnq) { 72056287Smckusick fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 72156287Smckusick vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 72256287Smckusick fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 72356287Smckusick vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 72456287Smckusick fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 72556287Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 72656287Smckusick fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 72756287Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 72856287Smckusick fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 72956287Smckusick } else { 73056287Smckusick vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 73156287Smckusick vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 73256287Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 73356287Smckusick vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 73458881Smckusick fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); 73558881Smckusick vap->va_flags = 0; 73656287Smckusick vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec); 73756287Smckusick vap->va_ctime.ts_nsec = 0; 73856287Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec); 73956287Smckusick vap->va_filerev = 0; 74056287Smckusick } 74157787Smckusick if (vap->va_size != np->n_size) { 74257787Smckusick if (vap->va_type == VREG) { 74357787Smckusick if (np->n_flag & NMODIFIED) { 74457787Smckusick if (vap->va_size < np->n_size) 74557787Smckusick vap->va_size = np->n_size; 74657787Smckusick else 74757787Smckusick np->n_size = vap->va_size; 74857787Smckusick } else 74957787Smckusick np->n_size = vap->va_size; 75057787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 75157787Smckusick } else 75257787Smckusick np->n_size = vap->va_size; 75345716Smckusick } 75438420Smckusick np->n_attrstamp = time.tv_sec; 75538420Smckusick *dposp = dpos; 75638420Smckusick *mdp = md; 75738884Smacklem if (vaper != NULL) { 75838420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 75957787Smckusick #ifdef notdef 76056660Smckusick if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) 76157787Smckusick if (np->n_size > vap->va_size) 76238884Smacklem vaper->va_size = np->n_size; 76357787Smckusick #endif 76453628Smckusick if (np->n_flag & NCHG) { 76554106Smckusick if (np->n_flag & NACC) { 76654106Smckusick vaper->va_atime.ts_sec = np->n_atim.tv_sec; 76754106Smckusick vaper->va_atime.ts_nsec = 76854106Smckusick np->n_atim.tv_usec * 1000; 76954106Smckusick } 77054106Smckusick if (np->n_flag & NUPD) { 77154106Smckusick vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 77254106Smckusick vaper->va_mtime.ts_nsec = 77354106Smckusick np->n_mtim.tv_usec * 1000; 77454106Smckusick } 77553628Smckusick } 77638884Smacklem } 77738420Smckusick return (0); 77838420Smckusick } 77938420Smckusick 78038420Smckusick /* 78138420Smckusick * Check the time stamp 78238420Smckusick * If the cache is valid, copy contents to *vap and return 0 78338420Smckusick * otherwise return an error 78438420Smckusick */ 78557787Smckusick nfs_getattrcache(vp, vaper) 78638420Smckusick register struct vnode *vp; 78757787Smckusick struct vattr *vaper; 78838420Smckusick { 78957787Smckusick register struct nfsnode *np = VTONFS(vp); 79057787Smckusick register struct vattr *vap; 79138420Smckusick 79256287Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 79352196Smckusick if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 79452196Smckusick nfsstats.attrcache_misses++; 79552196Smckusick return (ENOENT); 79652196Smckusick } 79756287Smckusick } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 79838420Smckusick nfsstats.attrcache_misses++; 79938420Smckusick return (ENOENT); 80038420Smckusick } 80152196Smckusick nfsstats.attrcache_hits++; 80257787Smckusick vap = &np->n_vattr; 80357787Smckusick if (vap->va_size != np->n_size) { 80457787Smckusick if (vap->va_type == VREG) { 80557787Smckusick if (np->n_flag & NMODIFIED) { 80657787Smckusick if (vap->va_size < np->n_size) 80757787Smckusick vap->va_size = np->n_size; 80857787Smckusick else 80957787Smckusick np->n_size = vap->va_size; 81057787Smckusick } else 81157787Smckusick np->n_size = vap->va_size; 81257787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 81357787Smckusick } else 81457787Smckusick np->n_size = vap->va_size; 81557787Smckusick } 81657787Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 81757787Smckusick #ifdef notdef 81856660Smckusick if ((np->n_flag & NMODIFIED) == 0) { 81957787Smckusick np->n_size = vaper->va_size; 82053322Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 82157787Smckusick } else if (np->n_size > vaper->va_size) 82257787Smckusick if (np->n_size > vaper->va_size) 82357787Smckusick vaper->va_size = np->n_size; 82457787Smckusick #endif 82553628Smckusick if (np->n_flag & NCHG) { 82654106Smckusick if (np->n_flag & NACC) { 82757787Smckusick vaper->va_atime.ts_sec = np->n_atim.tv_sec; 82857787Smckusick vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 82954106Smckusick } 83054106Smckusick if (np->n_flag & NUPD) { 83157787Smckusick vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 83257787Smckusick vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 83354106Smckusick } 83453628Smckusick } 83552196Smckusick return (0); 83638420Smckusick } 83738420Smckusick 83838420Smckusick /* 83952196Smckusick * Set up nameidata for a lookup() call and do it 84038420Smckusick */ 84152196Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 84238420Smckusick register struct nameidata *ndp; 84338420Smckusick fhandle_t *fhp; 84438420Smckusick int len; 84552196Smckusick struct nfssvc_sock *slp; 84652196Smckusick struct mbuf *nam; 84738420Smckusick struct mbuf **mdp; 84838420Smckusick caddr_t *dposp; 84949739Smckusick struct proc *p; 85038420Smckusick { 85138420Smckusick register int i, rem; 85238420Smckusick register struct mbuf *md; 85349739Smckusick register char *fromcp, *tocp; 85446514Smckusick struct vnode *dp; 85552315Sheideman int error, rdonly; 85652315Sheideman struct componentname *cnp = &ndp->ni_cnd; 85738420Smckusick 85852315Sheideman MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 85949739Smckusick /* 86049739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf 86149739Smckusick * and set the various ndp fields appropriately. 86249739Smckusick */ 86349739Smckusick fromcp = *dposp; 86452315Sheideman tocp = cnp->cn_pnbuf; 86549739Smckusick md = *mdp; 86649739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp; 86752315Sheideman cnp->cn_hash = 0; 86849739Smckusick for (i = 0; i < len; i++) { 86949739Smckusick while (rem == 0) { 87049739Smckusick md = md->m_next; 87149739Smckusick if (md == NULL) { 87249739Smckusick error = EBADRPC; 87349739Smckusick goto out; 87442244Smckusick } 87549739Smckusick fromcp = mtod(md, caddr_t); 87649739Smckusick rem = md->m_len; 87738420Smckusick } 87849739Smckusick if (*fromcp == '\0' || *fromcp == '/') { 87949739Smckusick error = EINVAL; 88049739Smckusick goto out; 88142244Smckusick } 88252315Sheideman cnp->cn_hash += (unsigned char)*fromcp; 88349739Smckusick *tocp++ = *fromcp++; 88449739Smckusick rem--; 88549739Smckusick } 88649739Smckusick *tocp = '\0'; 88749739Smckusick *mdp = md; 88849739Smckusick *dposp = fromcp; 88949739Smckusick len = nfsm_rndup(len)-len; 89049739Smckusick if (len > 0) { 89149739Smckusick if (rem >= len) 89249739Smckusick *dposp += len; 89349739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem)) 89449739Smckusick goto out; 89549739Smckusick } 89652315Sheideman ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 89752315Sheideman cnp->cn_nameptr = cnp->cn_pnbuf; 89846514Smckusick /* 89946514Smckusick * Extract and set starting directory. 90046514Smckusick */ 90152315Sheideman if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 90252315Sheideman nam, &rdonly)) 90349739Smckusick goto out; 90438425Smckusick if (dp->v_type != VDIR) { 90541902Smckusick vrele(dp); 90649739Smckusick error = ENOTDIR; 90749739Smckusick goto out; 90838425Smckusick } 90946514Smckusick ndp->ni_startdir = dp; 91052196Smckusick if (rdonly) 91152315Sheideman cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 91252196Smckusick else 91352315Sheideman cnp->cn_flags |= NOCROSSMOUNT; 91439345Smckusick /* 91549739Smckusick * And call lookup() to do the real work 91638420Smckusick */ 91752315Sheideman cnp->cn_proc = p; 91852315Sheideman if (error = lookup(ndp)) 91949739Smckusick goto out; 92049739Smckusick /* 92149739Smckusick * Check for encountering a symbolic link 92249739Smckusick */ 92352315Sheideman if (cnp->cn_flags & ISSYMLINK) { 92452315Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 92549739Smckusick vput(ndp->ni_dvp); 92649739Smckusick else 92749739Smckusick vrele(ndp->ni_dvp); 92849739Smckusick vput(ndp->ni_vp); 92949739Smckusick ndp->ni_vp = NULL; 93049739Smckusick error = EINVAL; 93149739Smckusick goto out; 93249739Smckusick } 93349739Smckusick /* 93449739Smckusick * Check for saved name request 93549739Smckusick */ 93652315Sheideman if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 93752315Sheideman cnp->cn_flags |= HASBUF; 93849739Smckusick return (0); 93949739Smckusick } 94049739Smckusick out: 94152315Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 94238420Smckusick return (error); 94338420Smckusick } 94438420Smckusick 94538420Smckusick /* 94638420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 94738420Smckusick * boundary and only trims off the back end 94838420Smckusick */ 94952196Smckusick void 95038420Smckusick nfsm_adj(mp, len, nul) 95138420Smckusick struct mbuf *mp; 95238420Smckusick register int len; 95338420Smckusick int nul; 95438420Smckusick { 95538420Smckusick register struct mbuf *m; 95638420Smckusick register int count, i; 95738420Smckusick register char *cp; 95838420Smckusick 95938420Smckusick /* 96038420Smckusick * Trim from tail. Scan the mbuf chain, 96138420Smckusick * calculating its length and finding the last mbuf. 96238420Smckusick * If the adjustment only affects this mbuf, then just 96338420Smckusick * adjust and return. Otherwise, rescan and truncate 96438420Smckusick * after the remaining size. 96538420Smckusick */ 96638420Smckusick count = 0; 96738420Smckusick m = mp; 96838420Smckusick for (;;) { 96938420Smckusick count += m->m_len; 97038420Smckusick if (m->m_next == (struct mbuf *)0) 97138420Smckusick break; 97238420Smckusick m = m->m_next; 97338420Smckusick } 97438579Smckusick if (m->m_len > len) { 97538420Smckusick m->m_len -= len; 97638420Smckusick if (nul > 0) { 97738420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 97838420Smckusick for (i = 0; i < nul; i++) 97938420Smckusick *cp++ = '\0'; 98038420Smckusick } 98138420Smckusick return; 98238420Smckusick } 98338420Smckusick count -= len; 98438420Smckusick if (count < 0) 98538420Smckusick count = 0; 98638420Smckusick /* 98738420Smckusick * Correct length for chain is "count". 98838420Smckusick * Find the mbuf with last data, adjust its length, 98938420Smckusick * and toss data from remaining mbufs on chain. 99038420Smckusick */ 99138420Smckusick for (m = mp; m; m = m->m_next) { 99238420Smckusick if (m->m_len >= count) { 99338420Smckusick m->m_len = count; 99438420Smckusick if (nul > 0) { 99538420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 99638420Smckusick for (i = 0; i < nul; i++) 99738420Smckusick *cp++ = '\0'; 99838420Smckusick } 99938420Smckusick break; 100038420Smckusick } 100138420Smckusick count -= m->m_len; 100238420Smckusick } 100338420Smckusick while (m = m->m_next) 100438420Smckusick m->m_len = 0; 100538420Smckusick } 100638420Smckusick 100738420Smckusick /* 100838420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 100938420Smckusick * - look up fsid in mount list (if not found ret error) 101054739Smckusick * - get vp and export rights by calling VFS_FHTOVP() 101154739Smckusick * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 101238420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 101338420Smckusick */ 101452196Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 101538420Smckusick fhandle_t *fhp; 101638420Smckusick int lockflag; 101738420Smckusick struct vnode **vpp; 101838420Smckusick struct ucred *cred; 101952196Smckusick struct nfssvc_sock *slp; 102052196Smckusick struct mbuf *nam; 102152196Smckusick int *rdonlyp; 102238420Smckusick { 102338420Smckusick register struct mount *mp; 102452196Smckusick register struct nfsuid *uidp; 102557787Smckusick register int i; 102654739Smckusick struct ucred *credanon; 102754739Smckusick int error, exflags; 102838420Smckusick 102952196Smckusick *vpp = (struct vnode *)0; 103038420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 103138420Smckusick return (ESTALE); 103254739Smckusick if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) 103354739Smckusick return (error); 103452196Smckusick /* 103552196Smckusick * Check/setup credentials. 103652196Smckusick */ 103754739Smckusick if (exflags & MNT_EXKERB) { 103852196Smckusick uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 103952196Smckusick while (uidp) { 104052196Smckusick if (uidp->nu_uid == cred->cr_uid) 104152196Smckusick break; 104252196Smckusick uidp = uidp->nu_hnext; 104345282Smckusick } 104452196Smckusick if (uidp) { 104557787Smckusick cred->cr_uid = uidp->nu_cr.cr_uid; 104657787Smckusick for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 104757787Smckusick cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 104857787Smckusick } else { 104957787Smckusick vput(*vpp); 105052196Smckusick return (NQNFS_AUTHERR); 105157787Smckusick } 105257787Smckusick } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 105357787Smckusick cred->cr_uid = credanon->cr_uid; 105457787Smckusick for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 105557787Smckusick cred->cr_groups[i] = credanon->cr_groups[i]; 105657787Smckusick } 105754739Smckusick if (exflags & MNT_EXRDONLY) 105852196Smckusick *rdonlyp = 1; 105945282Smckusick else 106052196Smckusick *rdonlyp = 0; 106152196Smckusick if (!lockflag) 106252196Smckusick VOP_UNLOCK(*vpp); 106352196Smckusick return (0); 106445282Smckusick } 106554988Smckusick 106654988Smckusick /* 106754988Smckusick * This function compares two net addresses by family and returns TRUE 106854988Smckusick * if they are the same host. 106954988Smckusick * If there is any doubt, return FALSE. 107054988Smckusick * The AF_INET family is handled as a special case so that address mbufs 107154988Smckusick * don't need to be saved to store "struct in_addr", which is only 4 bytes. 107254988Smckusick */ 107356363Smckusick netaddr_match(family, haddr, nam) 107454988Smckusick int family; 107554988Smckusick union nethostaddr *haddr; 107654988Smckusick struct mbuf *nam; 107754988Smckusick { 107854988Smckusick register struct sockaddr_in *inetaddr; 107954988Smckusick 108054988Smckusick switch (family) { 108154988Smckusick case AF_INET: 108254988Smckusick inetaddr = mtod(nam, struct sockaddr_in *); 108356363Smckusick if (inetaddr->sin_family == AF_INET && 108456363Smckusick inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 108554988Smckusick return (1); 108654988Smckusick break; 108754988Smckusick #ifdef ISO 108854988Smckusick case AF_ISO: 108956363Smckusick { 109056363Smckusick register struct sockaddr_iso *isoaddr1, *isoaddr2; 109156363Smckusick 109254988Smckusick isoaddr1 = mtod(nam, struct sockaddr_iso *); 109354988Smckusick isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 109456363Smckusick if (isoaddr1->siso_family == AF_ISO && 109556363Smckusick isoaddr1->siso_nlen > 0 && 109654988Smckusick isoaddr1->siso_nlen == isoaddr2->siso_nlen && 109754988Smckusick SAME_ISOADDR(isoaddr1, isoaddr2)) 109854988Smckusick return (1); 109954988Smckusick break; 110056363Smckusick } 110154988Smckusick #endif /* ISO */ 110254988Smckusick default: 110354988Smckusick break; 110454988Smckusick }; 110554988Smckusick return (0); 110654988Smckusick } 1107