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*56470Smckusick * @(#)nfs_subs.c 7.66 (Berkeley) 10/08/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 */ 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]; 64*56470Smckusick 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 } 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; 589*56470Smckusick 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 } 75156287Smckusick if (vap->va_size > np->n_size) { 75238884Smacklem np->n_size = vap->va_size; 75353322Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 75445716Smckusick } 75538420Smckusick np->n_attrstamp = time.tv_sec; 75638420Smckusick *dposp = dpos; 75738420Smckusick *mdp = md; 75838884Smacklem if (vaper != NULL) { 75938420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 76056287Smckusick if (np->n_size > vap->va_size) 76138884Smacklem vaper->va_size = np->n_size; 76253628Smckusick if (np->n_flag & NCHG) { 76354106Smckusick if (np->n_flag & NACC) { 76454106Smckusick vaper->va_atime.ts_sec = np->n_atim.tv_sec; 76554106Smckusick vaper->va_atime.ts_nsec = 76654106Smckusick np->n_atim.tv_usec * 1000; 76754106Smckusick } 76854106Smckusick if (np->n_flag & NUPD) { 76954106Smckusick vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 77054106Smckusick vaper->va_mtime.ts_nsec = 77154106Smckusick np->n_mtim.tv_usec * 1000; 77254106Smckusick } 77353628Smckusick } 77438884Smacklem } 77538420Smckusick return (0); 77638420Smckusick } 77738420Smckusick 77838420Smckusick /* 77938420Smckusick * Check the time stamp 78038420Smckusick * If the cache is valid, copy contents to *vap and return 0 78138420Smckusick * otherwise return an error 78238420Smckusick */ 78338420Smckusick nfs_getattrcache(vp, vap) 78438420Smckusick register struct vnode *vp; 78538420Smckusick struct vattr *vap; 78638420Smckusick { 78738420Smckusick register struct nfsnode *np; 78838420Smckusick 78938420Smckusick np = VTONFS(vp); 79056287Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 79152196Smckusick if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 79252196Smckusick nfsstats.attrcache_misses++; 79352196Smckusick return (ENOENT); 79452196Smckusick } 79556287Smckusick } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 79638420Smckusick nfsstats.attrcache_misses++; 79738420Smckusick return (ENOENT); 79838420Smckusick } 79952196Smckusick nfsstats.attrcache_hits++; 80052196Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 80156287Smckusick if (vap->va_size > np->n_size) { 80252196Smckusick np->n_size = vap->va_size; 80353322Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 80452196Smckusick } else if (np->n_size > vap->va_size) 80552196Smckusick vap->va_size = np->n_size; 80653628Smckusick if (np->n_flag & NCHG) { 80754106Smckusick if (np->n_flag & NACC) { 80854106Smckusick vap->va_atime.ts_sec = np->n_atim.tv_sec; 80954106Smckusick vap->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 81054106Smckusick } 81154106Smckusick if (np->n_flag & NUPD) { 81254106Smckusick vap->va_mtime.ts_sec = np->n_mtim.tv_sec; 81354106Smckusick vap->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 81454106Smckusick } 81553628Smckusick } 81652196Smckusick return (0); 81738420Smckusick } 81838420Smckusick 81938420Smckusick /* 82052196Smckusick * Set up nameidata for a lookup() call and do it 82138420Smckusick */ 82252196Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 82338420Smckusick register struct nameidata *ndp; 82438420Smckusick fhandle_t *fhp; 82538420Smckusick int len; 82652196Smckusick struct nfssvc_sock *slp; 82752196Smckusick struct mbuf *nam; 82838420Smckusick struct mbuf **mdp; 82938420Smckusick caddr_t *dposp; 83049739Smckusick struct proc *p; 83138420Smckusick { 83238420Smckusick register int i, rem; 83338420Smckusick register struct mbuf *md; 83449739Smckusick register char *fromcp, *tocp; 83546514Smckusick struct vnode *dp; 83652315Sheideman int error, rdonly; 83752315Sheideman struct componentname *cnp = &ndp->ni_cnd; 83838420Smckusick 83952315Sheideman MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 84049739Smckusick /* 84149739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf 84249739Smckusick * and set the various ndp fields appropriately. 84349739Smckusick */ 84449739Smckusick fromcp = *dposp; 84552315Sheideman tocp = cnp->cn_pnbuf; 84649739Smckusick md = *mdp; 84749739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp; 84852315Sheideman cnp->cn_hash = 0; 84949739Smckusick for (i = 0; i < len; i++) { 85049739Smckusick while (rem == 0) { 85149739Smckusick md = md->m_next; 85249739Smckusick if (md == NULL) { 85349739Smckusick error = EBADRPC; 85449739Smckusick goto out; 85542244Smckusick } 85649739Smckusick fromcp = mtod(md, caddr_t); 85749739Smckusick rem = md->m_len; 85838420Smckusick } 85949739Smckusick if (*fromcp == '\0' || *fromcp == '/') { 86049739Smckusick error = EINVAL; 86149739Smckusick goto out; 86242244Smckusick } 86349739Smckusick if (*fromcp & 0200) 86452315Sheideman if ((*fromcp&0377) == ('/'|0200) || cnp->cn_nameiop != DELETE) { 86549739Smckusick error = EINVAL; 86649739Smckusick goto out; 86749739Smckusick } 86852315Sheideman cnp->cn_hash += (unsigned char)*fromcp; 86949739Smckusick *tocp++ = *fromcp++; 87049739Smckusick rem--; 87149739Smckusick } 87249739Smckusick *tocp = '\0'; 87349739Smckusick *mdp = md; 87449739Smckusick *dposp = fromcp; 87549739Smckusick len = nfsm_rndup(len)-len; 87649739Smckusick if (len > 0) { 87749739Smckusick if (rem >= len) 87849739Smckusick *dposp += len; 87949739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem)) 88049739Smckusick goto out; 88149739Smckusick } 88252315Sheideman ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 88352315Sheideman cnp->cn_nameptr = cnp->cn_pnbuf; 88446514Smckusick /* 88546514Smckusick * Extract and set starting directory. 88646514Smckusick */ 88752315Sheideman if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 88852315Sheideman nam, &rdonly)) 88949739Smckusick goto out; 89038425Smckusick if (dp->v_type != VDIR) { 89141902Smckusick vrele(dp); 89249739Smckusick error = ENOTDIR; 89349739Smckusick goto out; 89438425Smckusick } 89546514Smckusick ndp->ni_startdir = dp; 89652196Smckusick if (rdonly) 89752315Sheideman cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 89852196Smckusick else 89952315Sheideman cnp->cn_flags |= NOCROSSMOUNT; 90039345Smckusick /* 90149739Smckusick * And call lookup() to do the real work 90238420Smckusick */ 90352315Sheideman cnp->cn_proc = p; 90452315Sheideman if (error = lookup(ndp)) 90549739Smckusick goto out; 90649739Smckusick /* 90749739Smckusick * Check for encountering a symbolic link 90849739Smckusick */ 90952315Sheideman if (cnp->cn_flags & ISSYMLINK) { 91052315Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 91149739Smckusick vput(ndp->ni_dvp); 91249739Smckusick else 91349739Smckusick vrele(ndp->ni_dvp); 91449739Smckusick vput(ndp->ni_vp); 91549739Smckusick ndp->ni_vp = NULL; 91649739Smckusick error = EINVAL; 91749739Smckusick goto out; 91849739Smckusick } 91949739Smckusick /* 92049739Smckusick * Check for saved name request 92149739Smckusick */ 92252315Sheideman if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 92352315Sheideman cnp->cn_flags |= HASBUF; 92449739Smckusick return (0); 92549739Smckusick } 92649739Smckusick out: 92752315Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 92838420Smckusick return (error); 92938420Smckusick } 93038420Smckusick 93138420Smckusick /* 93238420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 93338420Smckusick * boundary and only trims off the back end 93438420Smckusick */ 93552196Smckusick void 93638420Smckusick nfsm_adj(mp, len, nul) 93738420Smckusick struct mbuf *mp; 93838420Smckusick register int len; 93938420Smckusick int nul; 94038420Smckusick { 94138420Smckusick register struct mbuf *m; 94238420Smckusick register int count, i; 94338420Smckusick register char *cp; 94438420Smckusick 94538420Smckusick /* 94638420Smckusick * Trim from tail. Scan the mbuf chain, 94738420Smckusick * calculating its length and finding the last mbuf. 94838420Smckusick * If the adjustment only affects this mbuf, then just 94938420Smckusick * adjust and return. Otherwise, rescan and truncate 95038420Smckusick * after the remaining size. 95138420Smckusick */ 95238420Smckusick count = 0; 95338420Smckusick m = mp; 95438420Smckusick for (;;) { 95538420Smckusick count += m->m_len; 95638420Smckusick if (m->m_next == (struct mbuf *)0) 95738420Smckusick break; 95838420Smckusick m = m->m_next; 95938420Smckusick } 96038579Smckusick if (m->m_len > len) { 96138420Smckusick m->m_len -= len; 96238420Smckusick if (nul > 0) { 96338420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 96438420Smckusick for (i = 0; i < nul; i++) 96538420Smckusick *cp++ = '\0'; 96638420Smckusick } 96738420Smckusick return; 96838420Smckusick } 96938420Smckusick count -= len; 97038420Smckusick if (count < 0) 97138420Smckusick count = 0; 97238420Smckusick /* 97338420Smckusick * Correct length for chain is "count". 97438420Smckusick * Find the mbuf with last data, adjust its length, 97538420Smckusick * and toss data from remaining mbufs on chain. 97638420Smckusick */ 97738420Smckusick for (m = mp; m; m = m->m_next) { 97838420Smckusick if (m->m_len >= count) { 97938420Smckusick m->m_len = count; 98038420Smckusick if (nul > 0) { 98138420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 98238420Smckusick for (i = 0; i < nul; i++) 98338420Smckusick *cp++ = '\0'; 98438420Smckusick } 98538420Smckusick break; 98638420Smckusick } 98738420Smckusick count -= m->m_len; 98838420Smckusick } 98938420Smckusick while (m = m->m_next) 99038420Smckusick m->m_len = 0; 99138420Smckusick } 99238420Smckusick 99338420Smckusick /* 99438420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 99538420Smckusick * - look up fsid in mount list (if not found ret error) 99654739Smckusick * - get vp and export rights by calling VFS_FHTOVP() 99754739Smckusick * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 99838420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 99938420Smckusick */ 100052196Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 100138420Smckusick fhandle_t *fhp; 100238420Smckusick int lockflag; 100338420Smckusick struct vnode **vpp; 100438420Smckusick struct ucred *cred; 100552196Smckusick struct nfssvc_sock *slp; 100652196Smckusick struct mbuf *nam; 100752196Smckusick int *rdonlyp; 100838420Smckusick { 100938420Smckusick register struct mount *mp; 101052196Smckusick register struct nfsuid *uidp; 101154739Smckusick struct ucred *credanon; 101254739Smckusick int error, exflags; 101338420Smckusick 101452196Smckusick *vpp = (struct vnode *)0; 101538420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 101638420Smckusick return (ESTALE); 101754739Smckusick if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) 101854739Smckusick return (error); 101952196Smckusick /* 102052196Smckusick * Check/setup credentials. 102152196Smckusick */ 102254739Smckusick if (exflags & MNT_EXKERB) { 102352196Smckusick uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 102452196Smckusick while (uidp) { 102552196Smckusick if (uidp->nu_uid == cred->cr_uid) 102652196Smckusick break; 102752196Smckusick uidp = uidp->nu_hnext; 102845282Smckusick } 102952196Smckusick if (uidp) { 103052196Smckusick if (cred->cr_ref != 1) 103152196Smckusick panic("nsrv fhtovp"); 103252196Smckusick *cred = uidp->nu_cr; 103352196Smckusick } else 103452196Smckusick return (NQNFS_AUTHERR); 103554739Smckusick } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) 103654739Smckusick *cred = *credanon; 103754739Smckusick if (exflags & MNT_EXRDONLY) 103852196Smckusick *rdonlyp = 1; 103945282Smckusick else 104052196Smckusick *rdonlyp = 0; 104152196Smckusick if (!lockflag) 104252196Smckusick VOP_UNLOCK(*vpp); 104352196Smckusick return (0); 104445282Smckusick } 104554988Smckusick 104654988Smckusick /* 104754988Smckusick * This function compares two net addresses by family and returns TRUE 104854988Smckusick * if they are the same host. 104954988Smckusick * If there is any doubt, return FALSE. 105054988Smckusick * The AF_INET family is handled as a special case so that address mbufs 105154988Smckusick * don't need to be saved to store "struct in_addr", which is only 4 bytes. 105254988Smckusick */ 105356363Smckusick netaddr_match(family, haddr, nam) 105454988Smckusick int family; 105554988Smckusick union nethostaddr *haddr; 105654988Smckusick struct mbuf *nam; 105754988Smckusick { 105854988Smckusick register struct sockaddr_in *inetaddr; 105954988Smckusick 106054988Smckusick switch (family) { 106154988Smckusick case AF_INET: 106254988Smckusick inetaddr = mtod(nam, struct sockaddr_in *); 106356363Smckusick if (inetaddr->sin_family == AF_INET && 106456363Smckusick inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 106554988Smckusick return (1); 106654988Smckusick break; 106754988Smckusick #ifdef ISO 106854988Smckusick case AF_ISO: 106956363Smckusick { 107056363Smckusick register struct sockaddr_iso *isoaddr1, *isoaddr2; 107156363Smckusick 107254988Smckusick isoaddr1 = mtod(nam, struct sockaddr_iso *); 107354988Smckusick isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 107456363Smckusick if (isoaddr1->siso_family == AF_ISO && 107556363Smckusick isoaddr1->siso_nlen > 0 && 107654988Smckusick isoaddr1->siso_nlen == isoaddr2->siso_nlen && 107754988Smckusick SAME_ISOADDR(isoaddr1, isoaddr2)) 107854988Smckusick return (1); 107954988Smckusick break; 108056363Smckusick } 108154988Smckusick #endif /* ISO */ 108254988Smckusick default: 108354988Smckusick break; 108454988Smckusick }; 108554988Smckusick return (0); 108654988Smckusick } 1087