138420Smckusick /* 238420Smckusick * Copyright (c) 1989 The Regents of the University of California. 338420Smckusick * 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*57787Smckusick * @(#)nfs_subs.c 7.68 (Berkeley) 02/02/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 } 220*57787Smckusick 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. 39838420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 39952196Smckusick * (in this case it can never sleep, so it can be called from interrupt level) 40052196Smckusick * it may however block when Updateflg == False 40152196Smckusick * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 40238420Smckusick * cases. (The macros use the vars. dpos and dpos2) 40338420Smckusick */ 40438420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 40538420Smckusick struct mbuf **mdp; 40638420Smckusick caddr_t *dposp; 40738420Smckusick int siz; 40838420Smckusick int left; 40938420Smckusick int updateflg; 41038420Smckusick caddr_t *cp2; 41138420Smckusick { 41238420Smckusick register struct mbuf *mp, *mp2; 41338420Smckusick register int siz2, xfer; 41452196Smckusick register caddr_t p; 41538420Smckusick 41638420Smckusick mp = *mdp; 41738420Smckusick while (left == 0) { 41838420Smckusick *mdp = mp = mp->m_next; 41938420Smckusick if (mp == NULL) 42041902Smckusick return (EBADRPC); 42138420Smckusick left = mp->m_len; 42238420Smckusick *dposp = mtod(mp, caddr_t); 42338420Smckusick } 42438420Smckusick if (left >= siz) { 42538420Smckusick *cp2 = *dposp; 42638420Smckusick *dposp += siz; 42738420Smckusick } else if (mp->m_next == NULL) { 42841902Smckusick return (EBADRPC); 42941902Smckusick } else if (siz > MHLEN) { 43038420Smckusick panic("nfs S too big"); 43138420Smckusick } else { 43238420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 43338420Smckusick if (updateflg) { 43438420Smckusick NFSMINOFF(mp); 43538420Smckusick } else { 43638420Smckusick MGET(mp2, M_WAIT, MT_DATA); 43738420Smckusick mp2->m_next = mp->m_next; 43838420Smckusick mp->m_next = mp2; 43938420Smckusick mp->m_len -= left; 44038420Smckusick mp = mp2; 44138420Smckusick } 44252196Smckusick *cp2 = p = mtod(mp, caddr_t); 44352196Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 44438420Smckusick siz2 = siz-left; 44552196Smckusick p += left; 44638420Smckusick mp2 = mp->m_next; 44741902Smckusick /* Loop around copying up the siz2 bytes */ 44838420Smckusick while (siz2 > 0) { 44938420Smckusick if (mp2 == NULL) 45038420Smckusick return (EBADRPC); 45138420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 45241902Smckusick if (xfer > 0) { 45352196Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 45441902Smckusick NFSMADV(mp2, xfer); 45541902Smckusick mp2->m_len -= xfer; 45652196Smckusick p += xfer; 45741902Smckusick siz2 -= xfer; 45841902Smckusick } 45938420Smckusick if (siz2 > 0) 46038420Smckusick mp2 = mp2->m_next; 46138420Smckusick } 46238420Smckusick mp->m_len = siz; 46338420Smckusick *mdp = mp2; 46438420Smckusick *dposp = mtod(mp2, caddr_t); 46538420Smckusick } 46639494Smckusick return (0); 46738420Smckusick } 46838420Smckusick 46938420Smckusick /* 47041902Smckusick * Advance the position in the mbuf chain. 47138420Smckusick */ 47238420Smckusick nfs_adv(mdp, dposp, offs, left) 47338420Smckusick struct mbuf **mdp; 47438420Smckusick caddr_t *dposp; 47538420Smckusick int offs; 47638420Smckusick int left; 47738420Smckusick { 47838420Smckusick register struct mbuf *m; 47938420Smckusick register int s; 48038420Smckusick 48138420Smckusick m = *mdp; 48238420Smckusick s = left; 48338420Smckusick while (s < offs) { 48438420Smckusick offs -= s; 48538420Smckusick m = m->m_next; 48638420Smckusick if (m == NULL) 48741902Smckusick return (EBADRPC); 48838420Smckusick s = m->m_len; 48938420Smckusick } 49038420Smckusick *mdp = m; 49138420Smckusick *dposp = mtod(m, caddr_t)+offs; 49241902Smckusick return (0); 49338420Smckusick } 49438420Smckusick 49538420Smckusick /* 49638420Smckusick * Copy a string into mbufs for the hard cases... 49738420Smckusick */ 49838420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 49938420Smckusick struct mbuf **mb; 50038420Smckusick char **bpos; 50138420Smckusick char *cp; 50238420Smckusick long siz; 50338420Smckusick { 50438420Smckusick register struct mbuf *m1, *m2; 50538420Smckusick long left, xfer, len, tlen; 50648049Smckusick u_long *tl; 50738420Smckusick int putsize; 50838420Smckusick 50938420Smckusick putsize = 1; 51038420Smckusick m2 = *mb; 51152196Smckusick left = M_TRAILINGSPACE(m2); 51238420Smckusick if (left > 0) { 51348049Smckusick tl = ((u_long *)(*bpos)); 51448049Smckusick *tl++ = txdr_unsigned(siz); 51538420Smckusick putsize = 0; 51638420Smckusick left -= NFSX_UNSIGNED; 51738420Smckusick m2->m_len += NFSX_UNSIGNED; 51838420Smckusick if (left > 0) { 51948049Smckusick bcopy(cp, (caddr_t) tl, left); 52038420Smckusick siz -= left; 52138420Smckusick cp += left; 52238420Smckusick m2->m_len += left; 52338420Smckusick left = 0; 52438420Smckusick } 52538420Smckusick } 52652196Smckusick /* Loop around adding mbufs */ 52738420Smckusick while (siz > 0) { 52838420Smckusick MGET(m1, M_WAIT, MT_DATA); 52938420Smckusick if (siz > MLEN) 53041902Smckusick MCLGET(m1, M_WAIT); 53138420Smckusick m1->m_len = NFSMSIZ(m1); 53238420Smckusick m2->m_next = m1; 53338420Smckusick m2 = m1; 53448049Smckusick tl = mtod(m1, u_long *); 53538420Smckusick tlen = 0; 53638420Smckusick if (putsize) { 53748049Smckusick *tl++ = txdr_unsigned(siz); 53838420Smckusick m1->m_len -= NFSX_UNSIGNED; 53938420Smckusick tlen = NFSX_UNSIGNED; 54038420Smckusick putsize = 0; 54138420Smckusick } 54238420Smckusick if (siz < m1->m_len) { 54338420Smckusick len = nfsm_rndup(siz); 54438420Smckusick xfer = siz; 54538420Smckusick if (xfer < len) 54648049Smckusick *(tl+(xfer>>2)) = 0; 54738420Smckusick } else { 54838420Smckusick xfer = len = m1->m_len; 54938420Smckusick } 55048049Smckusick bcopy(cp, (caddr_t) tl, xfer); 55138420Smckusick m1->m_len = len+tlen; 55238420Smckusick siz -= xfer; 55338420Smckusick cp += xfer; 55438420Smckusick } 55538420Smckusick *mb = m1; 55638420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 55741902Smckusick return (0); 55838420Smckusick } 55938420Smckusick 56038420Smckusick /* 56138420Smckusick * Called once to initialize data structures... 56238420Smckusick */ 56339444Smckusick nfs_init() 56438420Smckusick { 56538420Smckusick register int i; 56652196Smckusick union nqsrvthead *lhp; 56738420Smckusick 56852196Smckusick nfsrtt.pos = 0; 56938420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 57038420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 57138420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 57238420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 57338420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 57438420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 57552196Smckusick rpc_autherr = txdr_unsigned(RPC_AUTHERR); 57652196Smckusick rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 57738420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 57852196Smckusick rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 57938420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 58038420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 58138420Smckusick nfs_true = txdr_unsigned(TRUE); 58238420Smckusick nfs_false = txdr_unsigned(FALSE); 58338420Smckusick /* Loop thru nfs procids */ 58438420Smckusick for (i = 0; i < NFS_NPROCS; i++) 58538420Smckusick nfs_procids[i] = txdr_unsigned(i); 58639345Smckusick /* Ensure async daemons disabled */ 58741902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 58839345Smckusick nfs_iodwant[i] = (struct proc *)0; 58956470Smckusick queue_init(&nfs_bufq); 59038420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 59138420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 59252979Smckusick nfsrv_init(0); /* Init server data structures */ 59339755Smckusick nfsrv_initcache(); /* Init the server request cache */ 59441902Smckusick 59541902Smckusick /* 59652196Smckusick * Initialize the nqnfs server stuff. 59752196Smckusick */ 59852196Smckusick if (nqnfsstarttime == 0) { 59952196Smckusick nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 60052196Smckusick + nqsrv_clockskew + nqsrv_writeslack; 60152196Smckusick NQLOADNOVRAM(nqnfsstarttime); 60252196Smckusick nqnfs_prog = txdr_unsigned(NQNFS_PROG); 60352196Smckusick nqnfs_vers = txdr_unsigned(NQNFS_VER1); 60452196Smckusick nqthead.th_head[0] = &nqthead; 60552196Smckusick nqthead.th_head[1] = &nqthead; 60655519Smckusick nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash); 60752196Smckusick } 60852196Smckusick 60952196Smckusick /* 61041902Smckusick * Initialize reply list and start timer 61141902Smckusick */ 61241902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 61338420Smckusick nfs_timer(); 61438420Smckusick } 61538420Smckusick 61638420Smckusick /* 61738420Smckusick * Attribute cache routines. 61838420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 61938420Smckusick * that are on the mbuf list 62038420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 62138420Smckusick * error otherwise 62238420Smckusick */ 62338420Smckusick 62438420Smckusick /* 62539444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 62638420Smckusick * the values on the mbuf list and 62738420Smckusick * Iff vap not NULL 62838420Smckusick * copy the attributes to *vaper 62938420Smckusick */ 63039457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 63139457Smckusick struct vnode **vpp; 63238420Smckusick struct mbuf **mdp; 63338420Smckusick caddr_t *dposp; 63438420Smckusick struct vattr *vaper; 63538420Smckusick { 63639457Smckusick register struct vnode *vp = *vpp; 63738420Smckusick register struct vattr *vap; 63838884Smacklem register struct nfsv2_fattr *fp; 63953553Sheideman extern int (**spec_nfsv2nodeop_p)(); 64055519Smckusick register struct nfsnode *np, *nq, **nhpp; 64139494Smckusick register long t1; 64239494Smckusick caddr_t dpos, cp2; 64356287Smckusick int error = 0, isnq; 64439494Smckusick struct mbuf *md; 64552196Smckusick enum vtype vtyp; 64652196Smckusick u_short vmode; 64742244Smckusick long rdev; 64856287Smckusick struct timespec mtime; 64939444Smckusick struct vnode *nvp; 65038420Smckusick 65138420Smckusick md = *mdp; 65238420Smckusick dpos = *dposp; 65352196Smckusick t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 65456287Smckusick isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 65556287Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, TRUE, &cp2)) 65638420Smckusick return (error); 65738884Smacklem fp = (struct nfsv2_fattr *)cp2; 65852196Smckusick vtyp = nfstov_type(fp->fa_type); 65952196Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode); 66053384Smckusick if (vtyp == VNON || vtyp == VREG) 66152196Smckusick vtyp = IFTOVT(vmode); 66256287Smckusick if (isnq) { 66356287Smckusick rdev = fxdr_unsigned(long, fp->fa_nqrdev); 66456287Smckusick fxdr_nqtime(&fp->fa_nqmtime, &mtime); 66556287Smckusick } else { 66656287Smckusick rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 66756287Smckusick fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 66856287Smckusick } 66939444Smckusick /* 67039444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 67139444Smckusick * n_mtime fields. Check to see if it represents a special 67239444Smckusick * device, and if so, check for a possible alias. Once the 67339444Smckusick * correct vnode has been obtained, fill in the rest of the 67439444Smckusick * information. 67539444Smckusick */ 67638420Smckusick np = VTONFS(vp); 67739444Smckusick if (vp->v_type == VNON) { 67852196Smckusick if (vtyp == VCHR && rdev == 0xffffffff) 67952196Smckusick vp->v_type = vtyp = VFIFO; 68042244Smckusick else 68152196Smckusick vp->v_type = vtyp; 68240295Smckusick if (vp->v_type == VFIFO) { 68340295Smckusick #ifdef FIFO 68453553Sheideman extern int (**fifo_nfsv2nodeop_p)(); 68553553Sheideman vp->v_op = fifo_nfsv2nodeop_p; 68640295Smckusick #else 68740295Smckusick return (EOPNOTSUPP); 68840295Smckusick #endif /* FIFO */ 68940295Smckusick } 69039444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 69153553Sheideman vp->v_op = spec_nfsv2nodeop_p; 69242244Smckusick if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 69339444Smckusick /* 69451984Smckusick * Discard unneeded vnode, but save its nfsnode. 69551984Smckusick */ 69655519Smckusick if (nq = np->n_forw) 69755519Smckusick nq->n_back = np->n_back; 69855519Smckusick *np->n_back = nq; 69951984Smckusick nvp->v_data = vp->v_data; 70051984Smckusick vp->v_data = NULL; 70153553Sheideman vp->v_op = spec_vnodeop_p; 70251984Smckusick vrele(vp); 70351984Smckusick vgone(vp); 70451984Smckusick /* 70539444Smckusick * Reinitialize aliased node. 70639444Smckusick */ 70739444Smckusick np->n_vnode = nvp; 70855519Smckusick nhpp = (struct nfsnode **)nfs_hash(&np->n_fh); 70955519Smckusick if (nq = *nhpp) 71055519Smckusick nq->n_back = &np->n_forw; 71155519Smckusick np->n_forw = nq; 71255519Smckusick np->n_back = nhpp; 71355519Smckusick *nhpp = np; 71451984Smckusick *vpp = vp = nvp; 71539444Smckusick } 71639444Smckusick } 71756287Smckusick np->n_mtime = mtime.ts_sec; 71839444Smckusick } 71938420Smckusick vap = &np->n_vattr; 72052196Smckusick vap->va_type = vtyp; 72152196Smckusick vap->va_mode = (vmode & 07777); 72238884Smacklem vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 72338884Smacklem vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 72438884Smacklem vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 72556287Smckusick vap->va_rdev = (dev_t)rdev; 72656287Smckusick vap->va_mtime = mtime; 72756287Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 72856287Smckusick if (isnq) { 72956287Smckusick fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 73056287Smckusick vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 73156287Smckusick fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 73256287Smckusick vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 73356287Smckusick fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 73456287Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 73556287Smckusick fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 73656287Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 73756287Smckusick fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 73856287Smckusick } else { 73956287Smckusick vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 74056287Smckusick vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 74156287Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 74256287Smckusick vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 74356287Smckusick vap->va_atime.ts_sec = fxdr_unsigned(long, fp->fa_nfsatime.nfs_sec); 74456287Smckusick vap->va_atime.ts_nsec = 0; 74556287Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_nfsatime.nfs_usec); 74656287Smckusick vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec); 74756287Smckusick vap->va_ctime.ts_nsec = 0; 74856287Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec); 74956287Smckusick vap->va_filerev = 0; 75056287Smckusick } 751*57787Smckusick if (vap->va_size != np->n_size) { 752*57787Smckusick if (vap->va_type == VREG) { 753*57787Smckusick if (np->n_flag & NMODIFIED) { 754*57787Smckusick if (vap->va_size < np->n_size) 755*57787Smckusick vap->va_size = np->n_size; 756*57787Smckusick else 757*57787Smckusick np->n_size = vap->va_size; 758*57787Smckusick } else 759*57787Smckusick np->n_size = vap->va_size; 760*57787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 761*57787Smckusick } else 762*57787Smckusick np->n_size = vap->va_size; 76345716Smckusick } 76438420Smckusick np->n_attrstamp = time.tv_sec; 76538420Smckusick *dposp = dpos; 76638420Smckusick *mdp = md; 76738884Smacklem if (vaper != NULL) { 76838420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 769*57787Smckusick #ifdef notdef 77056660Smckusick if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) 771*57787Smckusick if (np->n_size > vap->va_size) 77238884Smacklem vaper->va_size = np->n_size; 773*57787Smckusick #endif 77453628Smckusick if (np->n_flag & NCHG) { 77554106Smckusick if (np->n_flag & NACC) { 77654106Smckusick vaper->va_atime.ts_sec = np->n_atim.tv_sec; 77754106Smckusick vaper->va_atime.ts_nsec = 77854106Smckusick np->n_atim.tv_usec * 1000; 77954106Smckusick } 78054106Smckusick if (np->n_flag & NUPD) { 78154106Smckusick vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 78254106Smckusick vaper->va_mtime.ts_nsec = 78354106Smckusick np->n_mtim.tv_usec * 1000; 78454106Smckusick } 78553628Smckusick } 78638884Smacklem } 78738420Smckusick return (0); 78838420Smckusick } 78938420Smckusick 79038420Smckusick /* 79138420Smckusick * Check the time stamp 79238420Smckusick * If the cache is valid, copy contents to *vap and return 0 79338420Smckusick * otherwise return an error 79438420Smckusick */ 795*57787Smckusick nfs_getattrcache(vp, vaper) 79638420Smckusick register struct vnode *vp; 797*57787Smckusick struct vattr *vaper; 79838420Smckusick { 799*57787Smckusick register struct nfsnode *np = VTONFS(vp); 800*57787Smckusick register struct vattr *vap; 80138420Smckusick 80256287Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 80352196Smckusick if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 80452196Smckusick nfsstats.attrcache_misses++; 80552196Smckusick return (ENOENT); 80652196Smckusick } 80756287Smckusick } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 80838420Smckusick nfsstats.attrcache_misses++; 80938420Smckusick return (ENOENT); 81038420Smckusick } 81152196Smckusick nfsstats.attrcache_hits++; 812*57787Smckusick vap = &np->n_vattr; 813*57787Smckusick if (vap->va_size != np->n_size) { 814*57787Smckusick if (vap->va_type == VREG) { 815*57787Smckusick if (np->n_flag & NMODIFIED) { 816*57787Smckusick if (vap->va_size < np->n_size) 817*57787Smckusick vap->va_size = np->n_size; 818*57787Smckusick else 819*57787Smckusick np->n_size = vap->va_size; 820*57787Smckusick } else 821*57787Smckusick np->n_size = vap->va_size; 822*57787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 823*57787Smckusick } else 824*57787Smckusick np->n_size = vap->va_size; 825*57787Smckusick } 826*57787Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 827*57787Smckusick #ifdef notdef 82856660Smckusick if ((np->n_flag & NMODIFIED) == 0) { 829*57787Smckusick np->n_size = vaper->va_size; 83053322Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 831*57787Smckusick } else if (np->n_size > vaper->va_size) 832*57787Smckusick if (np->n_size > vaper->va_size) 833*57787Smckusick vaper->va_size = np->n_size; 834*57787Smckusick #endif 83553628Smckusick if (np->n_flag & NCHG) { 83654106Smckusick if (np->n_flag & NACC) { 837*57787Smckusick vaper->va_atime.ts_sec = np->n_atim.tv_sec; 838*57787Smckusick vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 83954106Smckusick } 84054106Smckusick if (np->n_flag & NUPD) { 841*57787Smckusick vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 842*57787Smckusick vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 84354106Smckusick } 84453628Smckusick } 84552196Smckusick return (0); 84638420Smckusick } 84738420Smckusick 84838420Smckusick /* 84952196Smckusick * Set up nameidata for a lookup() call and do it 85038420Smckusick */ 85152196Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 85238420Smckusick register struct nameidata *ndp; 85338420Smckusick fhandle_t *fhp; 85438420Smckusick int len; 85552196Smckusick struct nfssvc_sock *slp; 85652196Smckusick struct mbuf *nam; 85738420Smckusick struct mbuf **mdp; 85838420Smckusick caddr_t *dposp; 85949739Smckusick struct proc *p; 86038420Smckusick { 86138420Smckusick register int i, rem; 86238420Smckusick register struct mbuf *md; 86349739Smckusick register char *fromcp, *tocp; 86446514Smckusick struct vnode *dp; 86552315Sheideman int error, rdonly; 86652315Sheideman struct componentname *cnp = &ndp->ni_cnd; 86738420Smckusick 86852315Sheideman MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 86949739Smckusick /* 87049739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf 87149739Smckusick * and set the various ndp fields appropriately. 87249739Smckusick */ 87349739Smckusick fromcp = *dposp; 87452315Sheideman tocp = cnp->cn_pnbuf; 87549739Smckusick md = *mdp; 87649739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp; 87752315Sheideman cnp->cn_hash = 0; 87849739Smckusick for (i = 0; i < len; i++) { 87949739Smckusick while (rem == 0) { 88049739Smckusick md = md->m_next; 88149739Smckusick if (md == NULL) { 88249739Smckusick error = EBADRPC; 88349739Smckusick goto out; 88442244Smckusick } 88549739Smckusick fromcp = mtod(md, caddr_t); 88649739Smckusick rem = md->m_len; 88738420Smckusick } 88849739Smckusick if (*fromcp == '\0' || *fromcp == '/') { 88949739Smckusick error = EINVAL; 89049739Smckusick goto out; 89142244Smckusick } 89249739Smckusick if (*fromcp & 0200) 89352315Sheideman if ((*fromcp&0377) == ('/'|0200) || cnp->cn_nameiop != DELETE) { 89449739Smckusick error = EINVAL; 89549739Smckusick goto out; 89649739Smckusick } 89752315Sheideman cnp->cn_hash += (unsigned char)*fromcp; 89849739Smckusick *tocp++ = *fromcp++; 89949739Smckusick rem--; 90049739Smckusick } 90149739Smckusick *tocp = '\0'; 90249739Smckusick *mdp = md; 90349739Smckusick *dposp = fromcp; 90449739Smckusick len = nfsm_rndup(len)-len; 90549739Smckusick if (len > 0) { 90649739Smckusick if (rem >= len) 90749739Smckusick *dposp += len; 90849739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem)) 90949739Smckusick goto out; 91049739Smckusick } 91152315Sheideman ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 91252315Sheideman cnp->cn_nameptr = cnp->cn_pnbuf; 91346514Smckusick /* 91446514Smckusick * Extract and set starting directory. 91546514Smckusick */ 91652315Sheideman if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 91752315Sheideman nam, &rdonly)) 91849739Smckusick goto out; 91938425Smckusick if (dp->v_type != VDIR) { 92041902Smckusick vrele(dp); 92149739Smckusick error = ENOTDIR; 92249739Smckusick goto out; 92338425Smckusick } 92446514Smckusick ndp->ni_startdir = dp; 92552196Smckusick if (rdonly) 92652315Sheideman cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 92752196Smckusick else 92852315Sheideman cnp->cn_flags |= NOCROSSMOUNT; 92939345Smckusick /* 93049739Smckusick * And call lookup() to do the real work 93138420Smckusick */ 93252315Sheideman cnp->cn_proc = p; 93352315Sheideman if (error = lookup(ndp)) 93449739Smckusick goto out; 93549739Smckusick /* 93649739Smckusick * Check for encountering a symbolic link 93749739Smckusick */ 93852315Sheideman if (cnp->cn_flags & ISSYMLINK) { 93952315Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 94049739Smckusick vput(ndp->ni_dvp); 94149739Smckusick else 94249739Smckusick vrele(ndp->ni_dvp); 94349739Smckusick vput(ndp->ni_vp); 94449739Smckusick ndp->ni_vp = NULL; 94549739Smckusick error = EINVAL; 94649739Smckusick goto out; 94749739Smckusick } 94849739Smckusick /* 94949739Smckusick * Check for saved name request 95049739Smckusick */ 95152315Sheideman if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 95252315Sheideman cnp->cn_flags |= HASBUF; 95349739Smckusick return (0); 95449739Smckusick } 95549739Smckusick out: 95652315Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 95738420Smckusick return (error); 95838420Smckusick } 95938420Smckusick 96038420Smckusick /* 96138420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 96238420Smckusick * boundary and only trims off the back end 96338420Smckusick */ 96452196Smckusick void 96538420Smckusick nfsm_adj(mp, len, nul) 96638420Smckusick struct mbuf *mp; 96738420Smckusick register int len; 96838420Smckusick int nul; 96938420Smckusick { 97038420Smckusick register struct mbuf *m; 97138420Smckusick register int count, i; 97238420Smckusick register char *cp; 97338420Smckusick 97438420Smckusick /* 97538420Smckusick * Trim from tail. Scan the mbuf chain, 97638420Smckusick * calculating its length and finding the last mbuf. 97738420Smckusick * If the adjustment only affects this mbuf, then just 97838420Smckusick * adjust and return. Otherwise, rescan and truncate 97938420Smckusick * after the remaining size. 98038420Smckusick */ 98138420Smckusick count = 0; 98238420Smckusick m = mp; 98338420Smckusick for (;;) { 98438420Smckusick count += m->m_len; 98538420Smckusick if (m->m_next == (struct mbuf *)0) 98638420Smckusick break; 98738420Smckusick m = m->m_next; 98838420Smckusick } 98938579Smckusick if (m->m_len > len) { 99038420Smckusick m->m_len -= len; 99138420Smckusick if (nul > 0) { 99238420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 99338420Smckusick for (i = 0; i < nul; i++) 99438420Smckusick *cp++ = '\0'; 99538420Smckusick } 99638420Smckusick return; 99738420Smckusick } 99838420Smckusick count -= len; 99938420Smckusick if (count < 0) 100038420Smckusick count = 0; 100138420Smckusick /* 100238420Smckusick * Correct length for chain is "count". 100338420Smckusick * Find the mbuf with last data, adjust its length, 100438420Smckusick * and toss data from remaining mbufs on chain. 100538420Smckusick */ 100638420Smckusick for (m = mp; m; m = m->m_next) { 100738420Smckusick if (m->m_len >= count) { 100838420Smckusick m->m_len = count; 100938420Smckusick if (nul > 0) { 101038420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 101138420Smckusick for (i = 0; i < nul; i++) 101238420Smckusick *cp++ = '\0'; 101338420Smckusick } 101438420Smckusick break; 101538420Smckusick } 101638420Smckusick count -= m->m_len; 101738420Smckusick } 101838420Smckusick while (m = m->m_next) 101938420Smckusick m->m_len = 0; 102038420Smckusick } 102138420Smckusick 102238420Smckusick /* 102338420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 102438420Smckusick * - look up fsid in mount list (if not found ret error) 102554739Smckusick * - get vp and export rights by calling VFS_FHTOVP() 102654739Smckusick * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 102738420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 102838420Smckusick */ 102952196Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 103038420Smckusick fhandle_t *fhp; 103138420Smckusick int lockflag; 103238420Smckusick struct vnode **vpp; 103338420Smckusick struct ucred *cred; 103452196Smckusick struct nfssvc_sock *slp; 103552196Smckusick struct mbuf *nam; 103652196Smckusick int *rdonlyp; 103738420Smckusick { 103838420Smckusick register struct mount *mp; 103952196Smckusick register struct nfsuid *uidp; 1040*57787Smckusick register int i; 104154739Smckusick struct ucred *credanon; 104254739Smckusick int error, exflags; 104338420Smckusick 104452196Smckusick *vpp = (struct vnode *)0; 104538420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 104638420Smckusick return (ESTALE); 104754739Smckusick if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) 104854739Smckusick return (error); 104952196Smckusick /* 105052196Smckusick * Check/setup credentials. 105152196Smckusick */ 105254739Smckusick if (exflags & MNT_EXKERB) { 105352196Smckusick uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 105452196Smckusick while (uidp) { 105552196Smckusick if (uidp->nu_uid == cred->cr_uid) 105652196Smckusick break; 105752196Smckusick uidp = uidp->nu_hnext; 105845282Smckusick } 105952196Smckusick if (uidp) { 1060*57787Smckusick cred->cr_uid = uidp->nu_cr.cr_uid; 1061*57787Smckusick for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 1062*57787Smckusick cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 1063*57787Smckusick } else { 1064*57787Smckusick vput(*vpp); 106552196Smckusick return (NQNFS_AUTHERR); 1066*57787Smckusick } 1067*57787Smckusick } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1068*57787Smckusick cred->cr_uid = credanon->cr_uid; 1069*57787Smckusick for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1070*57787Smckusick cred->cr_groups[i] = credanon->cr_groups[i]; 1071*57787Smckusick } 107254739Smckusick if (exflags & MNT_EXRDONLY) 107352196Smckusick *rdonlyp = 1; 107445282Smckusick else 107552196Smckusick *rdonlyp = 0; 107652196Smckusick if (!lockflag) 107752196Smckusick VOP_UNLOCK(*vpp); 107852196Smckusick return (0); 107945282Smckusick } 108054988Smckusick 108154988Smckusick /* 108254988Smckusick * This function compares two net addresses by family and returns TRUE 108354988Smckusick * if they are the same host. 108454988Smckusick * If there is any doubt, return FALSE. 108554988Smckusick * The AF_INET family is handled as a special case so that address mbufs 108654988Smckusick * don't need to be saved to store "struct in_addr", which is only 4 bytes. 108754988Smckusick */ 108856363Smckusick netaddr_match(family, haddr, nam) 108954988Smckusick int family; 109054988Smckusick union nethostaddr *haddr; 109154988Smckusick struct mbuf *nam; 109254988Smckusick { 109354988Smckusick register struct sockaddr_in *inetaddr; 109454988Smckusick 109554988Smckusick switch (family) { 109654988Smckusick case AF_INET: 109754988Smckusick inetaddr = mtod(nam, struct sockaddr_in *); 109856363Smckusick if (inetaddr->sin_family == AF_INET && 109956363Smckusick inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 110054988Smckusick return (1); 110154988Smckusick break; 110254988Smckusick #ifdef ISO 110354988Smckusick case AF_ISO: 110456363Smckusick { 110556363Smckusick register struct sockaddr_iso *isoaddr1, *isoaddr2; 110656363Smckusick 110754988Smckusick isoaddr1 = mtod(nam, struct sockaddr_iso *); 110854988Smckusick isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 110956363Smckusick if (isoaddr1->siso_family == AF_ISO && 111056363Smckusick isoaddr1->siso_nlen > 0 && 111154988Smckusick isoaddr1->siso_nlen == isoaddr2->siso_nlen && 111254988Smckusick SAME_ISOADDR(isoaddr1, isoaddr2)) 111354988Smckusick return (1); 111454988Smckusick break; 111556363Smckusick } 111654988Smckusick #endif /* ISO */ 111754988Smckusick default: 111854988Smckusick break; 111954988Smckusick }; 112054988Smckusick return (0); 112154988Smckusick } 1122