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*52979Smckusick * @(#)nfs_subs.c 7.48 (Berkeley) 03/16/92 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 */ 1838420Smckusick #include "param.h" 1939345Smckusick #include "proc.h" 2045921Smckusick #include "filedesc.h" 2140136Smckusick #include "systm.h" 2240136Smckusick #include "kernel.h" 2338420Smckusick #include "mount.h" 2438420Smckusick #include "file.h" 2538420Smckusick #include "vnode.h" 2648049Smckusick #include "namei.h" 2740136Smckusick #include "mbuf.h" 2838884Smacklem #include "map.h" 2952196Smckusick #include "socket.h" 3047573Skarels 3151463Sbostic #include "ufs/ufs/quota.h" 3251463Sbostic #include "ufs/ufs/inode.h" 3352196Smckusick #include "ufs/ufs/ufsmount.h" 3447573Skarels 3538420Smckusick #include "rpcv2.h" 3638420Smckusick #include "nfsv2.h" 3752196Smckusick #include "nfsnode.h" 3851984Smckusick #include "nfs.h" 3938420Smckusick #include "xdr_subs.h" 4038420Smckusick #include "nfsm_subs.h" 4152196Smckusick #include "nfsmount.h" 4252196Smckusick #include "nqnfs.h" 4352196Smckusick #include "nfsrtt.h" 4438420Smckusick 4538420Smckusick #define TRUE 1 4638420Smckusick #define FALSE 0 4738420Smckusick 4838420Smckusick /* 4938420Smckusick * Data items converted to xdr at startup, since they are constant 5038420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 5138420Smckusick */ 5238420Smckusick u_long nfs_procids[NFS_NPROCS]; 5338420Smckusick u_long nfs_xdrneg1; 5452196Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 5552196Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 5652196Smckusick rpc_auth_kerb; 5738420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 5852196Smckusick 5938420Smckusick /* And other global data */ 6052196Smckusick static u_long nfs_xid = 0; 6142244Smckusick enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 6241902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 6341902Smckusick extern struct nfsreq nfsreqh; 6452196Smckusick extern int nqnfs_piggy[NFS_NPROCS]; 6552196Smckusick extern struct nfsrtt nfsrtt; 6652196Smckusick extern union nqsrvthead nqthead; 6752196Smckusick extern union nqsrvthead nqfhead[NQLCHSZ]; 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 } 21352196Smckusick 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 } 22052196Smckusick 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; 58938420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 59038420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 591*52979Smckusick nfsrv_init(0); /* Init server data structures */ 59239755Smckusick nfsrv_initcache(); /* Init the server request cache */ 59341902Smckusick 59441902Smckusick /* 59552196Smckusick * Initialize the nqnfs server stuff. 59652196Smckusick */ 59752196Smckusick if (nqnfsstarttime == 0) { 59852196Smckusick nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 59952196Smckusick + nqsrv_clockskew + nqsrv_writeslack; 60052196Smckusick NQLOADNOVRAM(nqnfsstarttime); 60152196Smckusick nqnfs_prog = txdr_unsigned(NQNFS_PROG); 60252196Smckusick nqnfs_vers = txdr_unsigned(NQNFS_VER1); 60352196Smckusick nqthead.th_head[0] = &nqthead; 60452196Smckusick nqthead.th_head[1] = &nqthead; 60552196Smckusick for (i = 0; i < NQLCHSZ; i++) { 60652196Smckusick lhp = &nqfhead[i]; 60752196Smckusick lhp->th_head[0] = lhp; 60852196Smckusick lhp->th_head[1] = lhp; 60952196Smckusick } 61052196Smckusick } 61152196Smckusick 61252196Smckusick /* 61341902Smckusick * Initialize reply list and start timer 61441902Smckusick */ 61541902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 61638420Smckusick nfs_timer(); 61738420Smckusick } 61838420Smckusick 61938420Smckusick /* 62038420Smckusick * Attribute cache routines. 62138420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 62238420Smckusick * that are on the mbuf list 62338420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 62438420Smckusick * error otherwise 62538420Smckusick */ 62638420Smckusick 62738420Smckusick /* 62839444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 62938420Smckusick * the values on the mbuf list and 63038420Smckusick * Iff vap not NULL 63138420Smckusick * copy the attributes to *vaper 63238420Smckusick */ 63339457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 63439457Smckusick struct vnode **vpp; 63538420Smckusick struct mbuf **mdp; 63638420Smckusick caddr_t *dposp; 63738420Smckusick struct vattr *vaper; 63838420Smckusick { 63939457Smckusick register struct vnode *vp = *vpp; 64038420Smckusick register struct vattr *vap; 64138884Smacklem register struct nfsv2_fattr *fp; 64251984Smckusick extern struct vnodeops spec_nfsv2nodeops, spec_vnodeops; 64339457Smckusick register struct nfsnode *np; 64439494Smckusick register long t1; 64539494Smckusick caddr_t dpos, cp2; 64639494Smckusick int error = 0; 64739494Smckusick struct mbuf *md; 64852196Smckusick enum vtype vtyp; 64952196Smckusick u_short vmode; 65042244Smckusick long rdev; 65139444Smckusick struct timeval mtime; 65239444Smckusick struct vnode *nvp; 65338420Smckusick 65438420Smckusick md = *mdp; 65538420Smckusick dpos = *dposp; 65652196Smckusick t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 65738420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 65838420Smckusick return (error); 65938884Smacklem fp = (struct nfsv2_fattr *)cp2; 66052196Smckusick vtyp = nfstov_type(fp->fa_type); 66152196Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode); 66252196Smckusick if (vtyp == VNON) 66352196Smckusick vtyp = IFTOVT(vmode); 66442244Smckusick rdev = fxdr_unsigned(long, fp->fa_rdev); 66539444Smckusick fxdr_time(&fp->fa_mtime, &mtime); 66639444Smckusick /* 66739444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 66839444Smckusick * n_mtime fields. Check to see if it represents a special 66939444Smckusick * device, and if so, check for a possible alias. Once the 67039444Smckusick * correct vnode has been obtained, fill in the rest of the 67139444Smckusick * information. 67239444Smckusick */ 67338420Smckusick np = VTONFS(vp); 67439444Smckusick if (vp->v_type == VNON) { 67552196Smckusick if (vtyp == VCHR && rdev == 0xffffffff) 67652196Smckusick vp->v_type = vtyp = VFIFO; 67742244Smckusick else 67852196Smckusick vp->v_type = vtyp; 67940295Smckusick if (vp->v_type == VFIFO) { 68040295Smckusick #ifdef FIFO 68140295Smckusick extern struct vnodeops fifo_nfsv2nodeops; 68240295Smckusick vp->v_op = &fifo_nfsv2nodeops; 68340295Smckusick #else 68440295Smckusick return (EOPNOTSUPP); 68540295Smckusick #endif /* FIFO */ 68640295Smckusick } 68739444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 68839444Smckusick vp->v_op = &spec_nfsv2nodeops; 68942244Smckusick if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 69039444Smckusick /* 69151984Smckusick * Discard unneeded vnode, but save its nfsnode. 69251984Smckusick */ 69351984Smckusick remque(np); 69451984Smckusick nvp->v_data = vp->v_data; 69551984Smckusick vp->v_data = NULL; 69651984Smckusick vp->v_op = &spec_vnodeops; 69751984Smckusick vrele(vp); 69851984Smckusick vgone(vp); 69951984Smckusick /* 70039444Smckusick * Reinitialize aliased node. 70139444Smckusick */ 70239444Smckusick np->n_vnode = nvp; 70351984Smckusick insque(np, nfs_hash(&np->n_fh)); 70451984Smckusick *vpp = vp = nvp; 70539444Smckusick } 70639444Smckusick } 70752196Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) 70852196Smckusick np->n_mtime = mtime.tv_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); 71638884Smacklem vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 71745716Smckusick if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) { 71838884Smacklem np->n_size = vap->va_size; 71945716Smckusick vnode_pager_setsize(vp, np->n_size); 72045716Smckusick } 72138884Smacklem vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 72242244Smckusick vap->va_rdev = (dev_t)rdev; 72342244Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 72442878Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 72538884Smacklem vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 72639755Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 72739755Smckusick vap->va_atime.tv_usec = 0; 72839755Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 72939444Smckusick vap->va_mtime = mtime; 73039755Smckusick vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 73139755Smckusick vap->va_ctime.tv_usec = 0; 73239755Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 73352024Smckusick #ifdef _NOQUAD 73452024Smckusick vap->va_size_rsv = 0; 73552024Smckusick vap->va_bytes_rsv = 0; 73652024Smckusick #endif 73738420Smckusick np->n_attrstamp = time.tv_sec; 73838420Smckusick *dposp = dpos; 73938420Smckusick *mdp = md; 74038884Smacklem if (vaper != NULL) { 74138420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 74238884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 74338884Smacklem vaper->va_size = np->n_size; 74438884Smacklem } 74538420Smckusick return (0); 74638420Smckusick } 74738420Smckusick 74838420Smckusick /* 74938420Smckusick * Check the time stamp 75038420Smckusick * If the cache is valid, copy contents to *vap and return 0 75138420Smckusick * otherwise return an error 75238420Smckusick */ 75338420Smckusick nfs_getattrcache(vp, vap) 75438420Smckusick register struct vnode *vp; 75538420Smckusick struct vattr *vap; 75638420Smckusick { 75738420Smckusick register struct nfsnode *np; 75838420Smckusick 75938420Smckusick np = VTONFS(vp); 76052196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 76152196Smckusick if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 76252196Smckusick nfsstats.attrcache_misses++; 76352196Smckusick return (ENOENT); 76452196Smckusick } 76552196Smckusick } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO) { 76638420Smckusick nfsstats.attrcache_misses++; 76738420Smckusick return (ENOENT); 76838420Smckusick } 76952196Smckusick nfsstats.attrcache_hits++; 77052196Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 77152196Smckusick if ((np->n_flag & NMODIFIED) == 0) { 77252196Smckusick np->n_size = vap->va_size; 77352196Smckusick vnode_pager_setsize(vp, np->n_size); 77452196Smckusick } else if (np->n_size > vap->va_size) 77552196Smckusick vap->va_size = np->n_size; 77652196Smckusick return (0); 77738420Smckusick } 77838420Smckusick 77938420Smckusick /* 78052196Smckusick * Set up nameidata for a lookup() call and do it 78138420Smckusick */ 78252196Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 78338420Smckusick register struct nameidata *ndp; 78438420Smckusick fhandle_t *fhp; 78538420Smckusick int len; 78652196Smckusick struct nfssvc_sock *slp; 78752196Smckusick struct mbuf *nam; 78838420Smckusick struct mbuf **mdp; 78938420Smckusick caddr_t *dposp; 79049739Smckusick struct proc *p; 79138420Smckusick { 79238420Smckusick register int i, rem; 79338420Smckusick register struct mbuf *md; 79449739Smckusick register char *fromcp, *tocp; 79546514Smckusick struct vnode *dp; 79652315Sheideman int error, rdonly; 79752315Sheideman struct componentname *cnp = &ndp->ni_cnd; 79838420Smckusick 79952315Sheideman MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 80049739Smckusick /* 80149739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf 80249739Smckusick * and set the various ndp fields appropriately. 80349739Smckusick */ 80449739Smckusick fromcp = *dposp; 80552315Sheideman tocp = cnp->cn_pnbuf; 80649739Smckusick md = *mdp; 80749739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp; 80852315Sheideman cnp->cn_hash = 0; 80949739Smckusick for (i = 0; i < len; i++) { 81049739Smckusick while (rem == 0) { 81149739Smckusick md = md->m_next; 81249739Smckusick if (md == NULL) { 81349739Smckusick error = EBADRPC; 81449739Smckusick goto out; 81542244Smckusick } 81649739Smckusick fromcp = mtod(md, caddr_t); 81749739Smckusick rem = md->m_len; 81838420Smckusick } 81949739Smckusick if (*fromcp == '\0' || *fromcp == '/') { 82049739Smckusick error = EINVAL; 82149739Smckusick goto out; 82242244Smckusick } 82349739Smckusick if (*fromcp & 0200) 82452315Sheideman if ((*fromcp&0377) == ('/'|0200) || cnp->cn_nameiop != DELETE) { 82549739Smckusick error = EINVAL; 82649739Smckusick goto out; 82749739Smckusick } 82852315Sheideman cnp->cn_hash += (unsigned char)*fromcp; 82949739Smckusick *tocp++ = *fromcp++; 83049739Smckusick rem--; 83149739Smckusick } 83249739Smckusick *tocp = '\0'; 83349739Smckusick *mdp = md; 83449739Smckusick *dposp = fromcp; 83549739Smckusick len = nfsm_rndup(len)-len; 83649739Smckusick if (len > 0) { 83749739Smckusick if (rem >= len) 83849739Smckusick *dposp += len; 83949739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem)) 84049739Smckusick goto out; 84149739Smckusick } 84252315Sheideman ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 84352315Sheideman cnp->cn_nameptr = cnp->cn_pnbuf; 84446514Smckusick /* 84546514Smckusick * Extract and set starting directory. 84646514Smckusick */ 84752315Sheideman if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 84852315Sheideman nam, &rdonly)) 84949739Smckusick goto out; 85038425Smckusick if (dp->v_type != VDIR) { 85141902Smckusick vrele(dp); 85249739Smckusick error = ENOTDIR; 85349739Smckusick goto out; 85438425Smckusick } 85546514Smckusick ndp->ni_startdir = dp; 85652196Smckusick if (rdonly) 85752315Sheideman cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 85852196Smckusick else 85952315Sheideman cnp->cn_flags |= NOCROSSMOUNT; 86039345Smckusick /* 86149739Smckusick * And call lookup() to do the real work 86238420Smckusick */ 86352315Sheideman cnp->cn_proc = p; 86452315Sheideman if (error = lookup(ndp)) 86549739Smckusick goto out; 86649739Smckusick /* 86749739Smckusick * Check for encountering a symbolic link 86849739Smckusick */ 86952315Sheideman if (cnp->cn_flags & ISSYMLINK) { 87052315Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 87149739Smckusick vput(ndp->ni_dvp); 87249739Smckusick else 87349739Smckusick vrele(ndp->ni_dvp); 87449739Smckusick vput(ndp->ni_vp); 87549739Smckusick ndp->ni_vp = NULL; 87649739Smckusick error = EINVAL; 87749739Smckusick goto out; 87849739Smckusick } 87949739Smckusick /* 88049739Smckusick * Check for saved name request 88149739Smckusick */ 88252315Sheideman if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 88352315Sheideman cnp->cn_flags |= HASBUF; 88449739Smckusick return (0); 88549739Smckusick } 88649739Smckusick out: 88752315Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 88838420Smckusick return (error); 88938420Smckusick } 89038420Smckusick 89138420Smckusick /* 89238420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 89338420Smckusick * boundary and only trims off the back end 89438420Smckusick */ 89552196Smckusick void 89638420Smckusick nfsm_adj(mp, len, nul) 89738420Smckusick struct mbuf *mp; 89838420Smckusick register int len; 89938420Smckusick int nul; 90038420Smckusick { 90138420Smckusick register struct mbuf *m; 90238420Smckusick register int count, i; 90338420Smckusick register char *cp; 90438420Smckusick 90538420Smckusick /* 90638420Smckusick * Trim from tail. Scan the mbuf chain, 90738420Smckusick * calculating its length and finding the last mbuf. 90838420Smckusick * If the adjustment only affects this mbuf, then just 90938420Smckusick * adjust and return. Otherwise, rescan and truncate 91038420Smckusick * after the remaining size. 91138420Smckusick */ 91238420Smckusick count = 0; 91338420Smckusick m = mp; 91438420Smckusick for (;;) { 91538420Smckusick count += m->m_len; 91638420Smckusick if (m->m_next == (struct mbuf *)0) 91738420Smckusick break; 91838420Smckusick m = m->m_next; 91938420Smckusick } 92038579Smckusick if (m->m_len > len) { 92138420Smckusick m->m_len -= len; 92238420Smckusick if (nul > 0) { 92338420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 92438420Smckusick for (i = 0; i < nul; i++) 92538420Smckusick *cp++ = '\0'; 92638420Smckusick } 92738420Smckusick return; 92838420Smckusick } 92938420Smckusick count -= len; 93038420Smckusick if (count < 0) 93138420Smckusick count = 0; 93238420Smckusick /* 93338420Smckusick * Correct length for chain is "count". 93438420Smckusick * Find the mbuf with last data, adjust its length, 93538420Smckusick * and toss data from remaining mbufs on chain. 93638420Smckusick */ 93738420Smckusick for (m = mp; m; m = m->m_next) { 93838420Smckusick if (m->m_len >= count) { 93938420Smckusick m->m_len = count; 94038420Smckusick if (nul > 0) { 94138420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 94238420Smckusick for (i = 0; i < nul; i++) 94338420Smckusick *cp++ = '\0'; 94438420Smckusick } 94538420Smckusick break; 94638420Smckusick } 94738420Smckusick count -= m->m_len; 94838420Smckusick } 94938420Smckusick while (m = m->m_next) 95038420Smckusick m->m_len = 0; 95138420Smckusick } 95238420Smckusick 95338420Smckusick /* 95438420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 95538420Smckusick * - look up fsid in mount list (if not found ret error) 95638420Smckusick * - check that it is exported 95738420Smckusick * - get vp by calling VFS_FHTOVP() macro 95838420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 95952196Smckusick * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to neth_anon 96038420Smckusick */ 96152196Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 96238420Smckusick fhandle_t *fhp; 96338420Smckusick int lockflag; 96438420Smckusick struct vnode **vpp; 96538420Smckusick struct ucred *cred; 96652196Smckusick struct nfssvc_sock *slp; 96752196Smckusick struct mbuf *nam; 96852196Smckusick int *rdonlyp; 96938420Smckusick { 97038420Smckusick register struct mount *mp; 97152196Smckusick register struct netaddrhash *np; 97252196Smckusick register struct ufsmount *ump; 97352196Smckusick register struct nfsuid *uidp; 97452196Smckusick struct sockaddr *saddr; 97552196Smckusick int error; 97638420Smckusick 97752196Smckusick *vpp = (struct vnode *)0; 97838420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 97938420Smckusick return (ESTALE); 98041398Smckusick if ((mp->mnt_flag & MNT_EXPORTED) == 0) 98138420Smckusick return (EACCES); 98245282Smckusick 98352196Smckusick /* 98452196Smckusick * Get the export permission structure for this <mp, client> tuple. 98552196Smckusick */ 98652196Smckusick ump = VFSTOUFS(mp); 98752196Smckusick if (nam) { 98845282Smckusick 98952196Smckusick /* 99052196Smckusick * First search for a network match. 99152196Smckusick */ 99252196Smckusick np = ump->um_netaddr[NETMASK_HASH]; 99352196Smckusick while (np) { 99452196Smckusick if (nfs_netaddr_match(np->neth_family, &np->neth_haddr, 99552196Smckusick &np->neth_hmask, nam)) 99652196Smckusick break; 99752196Smckusick np = np->neth_next; 99845282Smckusick } 99952196Smckusick 100052196Smckusick /* 100152196Smckusick * If not found, try for an address match. 100252196Smckusick */ 100352196Smckusick if (np == (struct netaddrhash *)0) { 100452196Smckusick saddr = mtod(nam, struct sockaddr *); 100552196Smckusick np = ump->um_netaddr[NETADDRHASH(saddr)]; 100652196Smckusick while (np) { 100752196Smckusick if (nfs_netaddr_match(np->neth_family, &np->neth_haddr, 100852196Smckusick (struct netaddrhash *)0, nam)) 100952196Smckusick break; 101052196Smckusick np = np->neth_next; 101152196Smckusick } 101245282Smckusick } 101352196Smckusick } else 101452196Smckusick np = (struct netaddrhash *)0; 101552196Smckusick if (np == (struct netaddrhash *)0) { 101652196Smckusick 101752196Smckusick /* 101852196Smckusick * If no address match, use the default if it exists. 101952196Smckusick */ 102052196Smckusick if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0) 102152196Smckusick return (EACCES); 102252196Smckusick np = &ump->um_defexported; 102345282Smckusick } 102452196Smckusick 102552196Smckusick /* 102652196Smckusick * Check/setup credentials. 102752196Smckusick */ 102852196Smckusick if (np->neth_exflags & MNT_EXKERB) { 102952196Smckusick uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 103052196Smckusick while (uidp) { 103152196Smckusick if (uidp->nu_uid == cred->cr_uid) 103252196Smckusick break; 103352196Smckusick uidp = uidp->nu_hnext; 103445282Smckusick } 103552196Smckusick if (uidp) { 103652196Smckusick if (cred->cr_ref != 1) 103752196Smckusick panic("nsrv fhtovp"); 103852196Smckusick *cred = uidp->nu_cr; 103952196Smckusick } else 104052196Smckusick return (NQNFS_AUTHERR); 104152196Smckusick } else if (cred->cr_uid == 0 || (np->neth_exflags & MNT_EXPORTANON)) 104252196Smckusick *cred = np->neth_anon; 104352196Smckusick if (error = VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp)) 104452196Smckusick return (ESTALE); 104552196Smckusick if (np->neth_exflags & MNT_EXRDONLY) 104652196Smckusick *rdonlyp = 1; 104745282Smckusick else 104852196Smckusick *rdonlyp = 0; 104952196Smckusick if (!lockflag) 105052196Smckusick VOP_UNLOCK(*vpp); 105152196Smckusick return (0); 105245282Smckusick } 1053