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*55703Smckusick * @(#)nfs_subs.c 7.62 (Berkeley) 07/25/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 39*55703Smckusick #include <miscfs/specfs/specdev.h> 40*55703Smckusick 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]; 6441902Smckusick extern struct nfsreq nfsreqh; 6552196Smckusick extern int nqnfs_piggy[NFS_NPROCS]; 6652196Smckusick extern struct nfsrtt nfsrtt; 6752196Smckusick extern time_t nqnfsstarttime; 6852196Smckusick extern u_long nqnfs_prog, nqnfs_vers; 6952196Smckusick extern int nqsrv_clockskew; 7052196Smckusick extern int nqsrv_writeslack; 7152196Smckusick extern int nqsrv_maxlease; 7238420Smckusick 7338420Smckusick /* 7438420Smckusick * Create the header for an rpc request packet 7538420Smckusick * The hsiz is the size of the rest of the nfs request header. 7638420Smckusick * (just used to decide if a cluster is a good idea) 7738420Smckusick */ 7852196Smckusick struct mbuf * 7952196Smckusick nfsm_reqh(vp, procid, hsiz, bposp) 8052196Smckusick struct vnode *vp; 8139494Smckusick u_long procid; 8238420Smckusick int hsiz; 8352196Smckusick caddr_t *bposp; 8438420Smckusick { 8552196Smckusick register struct mbuf *mb; 8648049Smckusick register u_long *tl; 8752196Smckusick register caddr_t bpos; 8852196Smckusick struct mbuf *mb2; 8952196Smckusick struct nfsmount *nmp; 9052196Smckusick int nqflag; 9138420Smckusick 9252196Smckusick MGET(mb, M_WAIT, MT_DATA); 9352196Smckusick if (hsiz >= MINCLSIZE) 9452196Smckusick MCLGET(mb, M_WAIT); 9552196Smckusick mb->m_len = 0; 9652196Smckusick bpos = mtod(mb, caddr_t); 9752196Smckusick 9852196Smckusick /* 9952196Smckusick * For NQNFS, add lease request. 10052196Smckusick */ 10152196Smckusick if (vp) { 10252196Smckusick nmp = VFSTONFS(vp->v_mount); 10352196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 10452196Smckusick nqflag = NQNFS_NEEDLEASE(vp, procid); 10552196Smckusick if (nqflag) { 10652196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 10752196Smckusick *tl++ = txdr_unsigned(nqflag); 10852196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 10952196Smckusick } else { 11052196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 11152196Smckusick *tl = 0; 11252196Smckusick } 11352196Smckusick } 11452196Smckusick } 11552196Smckusick /* Finally, return values */ 11652196Smckusick *bposp = bpos; 11752196Smckusick return (mb); 11852196Smckusick } 11938420Smckusick 12052196Smckusick /* 12152196Smckusick * Build the RPC header and fill in the authorization info. 12252196Smckusick * The authorization string argument is only used when the credentials 12352196Smckusick * come from outside of the kernel. 12452196Smckusick * Returns the head of the mbuf list. 12552196Smckusick */ 12652196Smckusick struct mbuf * 12752196Smckusick nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 12852196Smckusick mrest_len, mbp, xidp) 12952196Smckusick register struct ucred *cr; 13052196Smckusick int nqnfs; 13152196Smckusick int procid; 13252196Smckusick int auth_type; 13352196Smckusick int auth_len; 13452196Smckusick char *auth_str; 13552196Smckusick struct mbuf *mrest; 13652196Smckusick int mrest_len; 13752196Smckusick struct mbuf **mbp; 13852196Smckusick u_long *xidp; 13952196Smckusick { 14052196Smckusick register struct mbuf *mb; 14152196Smckusick register u_long *tl; 14252196Smckusick register caddr_t bpos; 14352196Smckusick register int i; 14452196Smckusick struct mbuf *mreq, *mb2; 14552196Smckusick int siz, grpsiz, authsiz; 14652196Smckusick 14752196Smckusick authsiz = nfsm_rndup(auth_len); 14852196Smckusick if (auth_type == RPCAUTH_NQNFS) 14952196Smckusick authsiz += 2 * NFSX_UNSIGNED; 15052196Smckusick MGETHDR(mb, M_WAIT, MT_DATA); 15152196Smckusick if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 15252196Smckusick MCLGET(mb, M_WAIT); 15352196Smckusick } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 15452196Smckusick MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 15552196Smckusick } else { 15652196Smckusick MH_ALIGN(mb, 8*NFSX_UNSIGNED); 15752196Smckusick } 15852196Smckusick mb->m_len = 0; 15952196Smckusick mreq = mb; 16052196Smckusick bpos = mtod(mb, caddr_t); 16152196Smckusick 16238420Smckusick /* 16352196Smckusick * First the RPC header. 16438420Smckusick */ 16552196Smckusick nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 16652196Smckusick if (++nfs_xid == 0) 16752196Smckusick nfs_xid++; 16852196Smckusick *tl++ = *xidp = txdr_unsigned(nfs_xid); 16948049Smckusick *tl++ = rpc_call; 17048049Smckusick *tl++ = rpc_vers; 17152196Smckusick if (nqnfs) { 17252196Smckusick *tl++ = txdr_unsigned(NQNFS_PROG); 17352196Smckusick *tl++ = txdr_unsigned(NQNFS_VER1); 17452196Smckusick } else { 17552196Smckusick *tl++ = txdr_unsigned(NFS_PROG); 17652196Smckusick *tl++ = txdr_unsigned(NFS_VER2); 17752196Smckusick } 17852196Smckusick *tl++ = txdr_unsigned(procid); 17938420Smckusick 18052196Smckusick /* 18152196Smckusick * And then the authorization cred. 18252196Smckusick */ 18352196Smckusick *tl++ = txdr_unsigned(auth_type); 18452196Smckusick *tl = txdr_unsigned(authsiz); 18552196Smckusick switch (auth_type) { 18652196Smckusick case RPCAUTH_UNIX: 18752196Smckusick nfsm_build(tl, u_long *, auth_len); 18852196Smckusick *tl++ = 0; /* stamp ?? */ 18952196Smckusick *tl++ = 0; /* NULL hostname */ 19052196Smckusick *tl++ = txdr_unsigned(cr->cr_uid); 19152196Smckusick *tl++ = txdr_unsigned(cr->cr_groups[0]); 19252196Smckusick grpsiz = (auth_len >> 2) - 5; 19352196Smckusick *tl++ = txdr_unsigned(grpsiz); 19452196Smckusick for (i = 1; i <= grpsiz; i++) 19552196Smckusick *tl++ = txdr_unsigned(cr->cr_groups[i]); 19652196Smckusick break; 19752196Smckusick case RPCAUTH_NQNFS: 19852196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 19952196Smckusick *tl++ = txdr_unsigned(cr->cr_uid); 20052196Smckusick *tl = txdr_unsigned(auth_len); 20152196Smckusick siz = auth_len; 20252196Smckusick while (siz > 0) { 20352196Smckusick if (M_TRAILINGSPACE(mb) == 0) { 20452196Smckusick MGET(mb2, M_WAIT, MT_DATA); 20552196Smckusick if (siz >= MINCLSIZE) 20652196Smckusick MCLGET(mb2, M_WAIT); 20752196Smckusick mb->m_next = mb2; 20852196Smckusick mb = mb2; 20952196Smckusick mb->m_len = 0; 21052196Smckusick bpos = mtod(mb, caddr_t); 21152196Smckusick } 21255057Spendry i = min(siz, M_TRAILINGSPACE(mb)); 21352196Smckusick bcopy(auth_str, bpos, i); 21452196Smckusick mb->m_len += i; 21552196Smckusick auth_str += i; 21652196Smckusick bpos += i; 21752196Smckusick siz -= i; 21838420Smckusick } 21952196Smckusick if ((siz = nfsm_rndup(auth_len) - auth_len) > 0) { 22052196Smckusick for (i = 0; i < siz; i++) 22152196Smckusick *bpos++ = '\0'; 22252196Smckusick mb->m_len += siz; 22352196Smckusick } 22452196Smckusick break; 22552196Smckusick }; 22652196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 22752196Smckusick *tl++ = txdr_unsigned(RPCAUTH_NULL); 22852196Smckusick *tl = 0; 22952196Smckusick mb->m_next = mrest; 23052196Smckusick mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 23152196Smckusick mreq->m_pkthdr.rcvif = (struct ifnet *)0; 23252196Smckusick *mbp = mb; 23338420Smckusick return (mreq); 23438420Smckusick } 23538420Smckusick 23638420Smckusick /* 23738420Smckusick * copies mbuf chain to the uio scatter/gather list 23838420Smckusick */ 23938420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 24038420Smckusick struct mbuf **mrep; 24143353Smckusick register struct uio *uiop; 24238420Smckusick int siz; 24338420Smckusick caddr_t *dpos; 24438420Smckusick { 24543353Smckusick register char *mbufcp, *uiocp; 24638420Smckusick register int xfer, left, len; 24738420Smckusick register struct mbuf *mp; 24838420Smckusick long uiosiz, rem; 24941902Smckusick int error = 0; 25038420Smckusick 25138420Smckusick mp = *mrep; 25238420Smckusick mbufcp = *dpos; 25338420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 25438420Smckusick rem = nfsm_rndup(siz)-siz; 25538420Smckusick while (siz > 0) { 25638420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 25741902Smckusick return (EFBIG); 25838420Smckusick left = uiop->uio_iov->iov_len; 25938420Smckusick uiocp = uiop->uio_iov->iov_base; 26038420Smckusick if (left > siz) 26138420Smckusick left = siz; 26238420Smckusick uiosiz = left; 26338420Smckusick while (left > 0) { 26438420Smckusick while (len == 0) { 26538420Smckusick mp = mp->m_next; 26638420Smckusick if (mp == NULL) 26738420Smckusick return (EBADRPC); 26838420Smckusick mbufcp = mtod(mp, caddr_t); 26938420Smckusick len = mp->m_len; 27038420Smckusick } 27138420Smckusick xfer = (left > len) ? len : left; 27238420Smckusick #ifdef notdef 27338420Smckusick /* Not Yet.. */ 27438420Smckusick if (uiop->uio_iov->iov_op != NULL) 27538420Smckusick (*(uiop->uio_iov->iov_op)) 27638420Smckusick (mbufcp, uiocp, xfer); 27738420Smckusick else 27838420Smckusick #endif 27938420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 28038420Smckusick bcopy(mbufcp, uiocp, xfer); 28138420Smckusick else 28238420Smckusick copyout(mbufcp, uiocp, xfer); 28338420Smckusick left -= xfer; 28438420Smckusick len -= xfer; 28538420Smckusick mbufcp += xfer; 28638420Smckusick uiocp += xfer; 28739585Smckusick uiop->uio_offset += xfer; 28838420Smckusick uiop->uio_resid -= xfer; 28938420Smckusick } 29038420Smckusick if (uiop->uio_iov->iov_len <= siz) { 29138420Smckusick uiop->uio_iovcnt--; 29238420Smckusick uiop->uio_iov++; 29338420Smckusick } else { 29438420Smckusick uiop->uio_iov->iov_base += uiosiz; 29538420Smckusick uiop->uio_iov->iov_len -= uiosiz; 29638420Smckusick } 29738420Smckusick siz -= uiosiz; 29838420Smckusick } 29938420Smckusick *dpos = mbufcp; 30038420Smckusick *mrep = mp; 30141902Smckusick if (rem > 0) { 30241902Smckusick if (len < rem) 30341902Smckusick error = nfs_adv(mrep, dpos, rem, len); 30441902Smckusick else 30541902Smckusick *dpos += rem; 30641902Smckusick } 30741902Smckusick return (error); 30838420Smckusick } 30938420Smckusick 31038420Smckusick /* 31138420Smckusick * copies a uio scatter/gather list to an mbuf chain... 31238420Smckusick */ 31338420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 31438420Smckusick register struct uio *uiop; 31538420Smckusick struct mbuf **mq; 31638420Smckusick int siz; 31738420Smckusick caddr_t *bpos; 31838420Smckusick { 31943353Smckusick register char *uiocp; 32043353Smckusick register struct mbuf *mp, *mp2; 32152196Smckusick register int xfer, left, mlen; 32243353Smckusick int uiosiz, clflg, rem; 32343353Smckusick char *cp; 32438420Smckusick 32538420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 32638420Smckusick clflg = 1; 32738420Smckusick else 32838420Smckusick clflg = 0; 32938420Smckusick rem = nfsm_rndup(siz)-siz; 33052196Smckusick mp = mp2 = *mq; 33138420Smckusick while (siz > 0) { 33238420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 33341902Smckusick return (EINVAL); 33438420Smckusick left = uiop->uio_iov->iov_len; 33538420Smckusick uiocp = uiop->uio_iov->iov_base; 33638420Smckusick if (left > siz) 33738420Smckusick left = siz; 33838420Smckusick uiosiz = left; 33938420Smckusick while (left > 0) { 34052196Smckusick mlen = M_TRAILINGSPACE(mp); 34152196Smckusick if (mlen == 0) { 34252196Smckusick MGET(mp, M_WAIT, MT_DATA); 34352196Smckusick if (clflg) 34452196Smckusick MCLGET(mp, M_WAIT); 34552196Smckusick mp->m_len = 0; 34652196Smckusick mp2->m_next = mp; 34752196Smckusick mp2 = mp; 34852196Smckusick mlen = M_TRAILINGSPACE(mp); 34952196Smckusick } 35052196Smckusick xfer = (left > mlen) ? mlen : left; 35138420Smckusick #ifdef notdef 35238420Smckusick /* Not Yet.. */ 35338420Smckusick if (uiop->uio_iov->iov_op != NULL) 35438420Smckusick (*(uiop->uio_iov->iov_op)) 35552196Smckusick (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 35638420Smckusick else 35738420Smckusick #endif 35838420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 35952196Smckusick bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 36038420Smckusick else 36152196Smckusick copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 36252196Smckusick mp->m_len += xfer; 36338420Smckusick left -= xfer; 36438420Smckusick uiocp += xfer; 36539585Smckusick uiop->uio_offset += xfer; 36638420Smckusick uiop->uio_resid -= xfer; 36738420Smckusick } 36838420Smckusick if (uiop->uio_iov->iov_len <= siz) { 36938420Smckusick uiop->uio_iovcnt--; 37038420Smckusick uiop->uio_iov++; 37138420Smckusick } else { 37238420Smckusick uiop->uio_iov->iov_base += uiosiz; 37338420Smckusick uiop->uio_iov->iov_len -= uiosiz; 37438420Smckusick } 37538420Smckusick siz -= uiosiz; 37638420Smckusick } 37738420Smckusick if (rem > 0) { 37852196Smckusick if (rem > M_TRAILINGSPACE(mp)) { 37938420Smckusick MGET(mp, M_WAIT, MT_DATA); 38038420Smckusick mp->m_len = 0; 38138420Smckusick mp2->m_next = mp; 38238420Smckusick } 38338420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 38438420Smckusick for (left = 0; left < rem; left++) 38538420Smckusick *cp++ = '\0'; 38638420Smckusick mp->m_len += rem; 38738420Smckusick *bpos = cp; 38838420Smckusick } else 38938420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 39038420Smckusick *mq = mp; 39141902Smckusick return (0); 39238420Smckusick } 39338420Smckusick 39438420Smckusick /* 39538420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 39638420Smckusick * pointed to by returned val. 39738420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 39852196Smckusick * (in this case it can never sleep, so it can be called from interrupt level) 39952196Smckusick * it may however block when Updateflg == False 40052196Smckusick * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 40138420Smckusick * cases. (The macros use the vars. dpos and dpos2) 40238420Smckusick */ 40338420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 40438420Smckusick struct mbuf **mdp; 40538420Smckusick caddr_t *dposp; 40638420Smckusick int siz; 40738420Smckusick int left; 40838420Smckusick int updateflg; 40938420Smckusick caddr_t *cp2; 41038420Smckusick { 41138420Smckusick register struct mbuf *mp, *mp2; 41238420Smckusick register int siz2, xfer; 41352196Smckusick register caddr_t p; 41438420Smckusick 41538420Smckusick mp = *mdp; 41638420Smckusick while (left == 0) { 41738420Smckusick *mdp = mp = mp->m_next; 41838420Smckusick if (mp == NULL) 41941902Smckusick return (EBADRPC); 42038420Smckusick left = mp->m_len; 42138420Smckusick *dposp = mtod(mp, caddr_t); 42238420Smckusick } 42338420Smckusick if (left >= siz) { 42438420Smckusick *cp2 = *dposp; 42538420Smckusick *dposp += siz; 42638420Smckusick } else if (mp->m_next == NULL) { 42741902Smckusick return (EBADRPC); 42841902Smckusick } else if (siz > MHLEN) { 42938420Smckusick panic("nfs S too big"); 43038420Smckusick } else { 43138420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 43238420Smckusick if (updateflg) { 43338420Smckusick NFSMINOFF(mp); 43438420Smckusick } else { 43538420Smckusick MGET(mp2, M_WAIT, MT_DATA); 43638420Smckusick mp2->m_next = mp->m_next; 43738420Smckusick mp->m_next = mp2; 43838420Smckusick mp->m_len -= left; 43938420Smckusick mp = mp2; 44038420Smckusick } 44152196Smckusick *cp2 = p = mtod(mp, caddr_t); 44252196Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 44338420Smckusick siz2 = siz-left; 44452196Smckusick p += left; 44538420Smckusick mp2 = mp->m_next; 44641902Smckusick /* Loop around copying up the siz2 bytes */ 44738420Smckusick while (siz2 > 0) { 44838420Smckusick if (mp2 == NULL) 44938420Smckusick return (EBADRPC); 45038420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 45141902Smckusick if (xfer > 0) { 45252196Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 45341902Smckusick NFSMADV(mp2, xfer); 45441902Smckusick mp2->m_len -= xfer; 45552196Smckusick p += xfer; 45641902Smckusick siz2 -= xfer; 45741902Smckusick } 45838420Smckusick if (siz2 > 0) 45938420Smckusick mp2 = mp2->m_next; 46038420Smckusick } 46138420Smckusick mp->m_len = siz; 46238420Smckusick *mdp = mp2; 46338420Smckusick *dposp = mtod(mp2, caddr_t); 46438420Smckusick } 46539494Smckusick return (0); 46638420Smckusick } 46738420Smckusick 46838420Smckusick /* 46941902Smckusick * Advance the position in the mbuf chain. 47038420Smckusick */ 47138420Smckusick nfs_adv(mdp, dposp, offs, left) 47238420Smckusick struct mbuf **mdp; 47338420Smckusick caddr_t *dposp; 47438420Smckusick int offs; 47538420Smckusick int left; 47638420Smckusick { 47738420Smckusick register struct mbuf *m; 47838420Smckusick register int s; 47938420Smckusick 48038420Smckusick m = *mdp; 48138420Smckusick s = left; 48238420Smckusick while (s < offs) { 48338420Smckusick offs -= s; 48438420Smckusick m = m->m_next; 48538420Smckusick if (m == NULL) 48641902Smckusick return (EBADRPC); 48738420Smckusick s = m->m_len; 48838420Smckusick } 48938420Smckusick *mdp = m; 49038420Smckusick *dposp = mtod(m, caddr_t)+offs; 49141902Smckusick return (0); 49238420Smckusick } 49338420Smckusick 49438420Smckusick /* 49538420Smckusick * Copy a string into mbufs for the hard cases... 49638420Smckusick */ 49738420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 49838420Smckusick struct mbuf **mb; 49938420Smckusick char **bpos; 50038420Smckusick char *cp; 50138420Smckusick long siz; 50238420Smckusick { 50338420Smckusick register struct mbuf *m1, *m2; 50438420Smckusick long left, xfer, len, tlen; 50548049Smckusick u_long *tl; 50638420Smckusick int putsize; 50738420Smckusick 50838420Smckusick putsize = 1; 50938420Smckusick m2 = *mb; 51052196Smckusick left = M_TRAILINGSPACE(m2); 51138420Smckusick if (left > 0) { 51248049Smckusick tl = ((u_long *)(*bpos)); 51348049Smckusick *tl++ = txdr_unsigned(siz); 51438420Smckusick putsize = 0; 51538420Smckusick left -= NFSX_UNSIGNED; 51638420Smckusick m2->m_len += NFSX_UNSIGNED; 51738420Smckusick if (left > 0) { 51848049Smckusick bcopy(cp, (caddr_t) tl, left); 51938420Smckusick siz -= left; 52038420Smckusick cp += left; 52138420Smckusick m2->m_len += left; 52238420Smckusick left = 0; 52338420Smckusick } 52438420Smckusick } 52552196Smckusick /* Loop around adding mbufs */ 52638420Smckusick while (siz > 0) { 52738420Smckusick MGET(m1, M_WAIT, MT_DATA); 52838420Smckusick if (siz > MLEN) 52941902Smckusick MCLGET(m1, M_WAIT); 53038420Smckusick m1->m_len = NFSMSIZ(m1); 53138420Smckusick m2->m_next = m1; 53238420Smckusick m2 = m1; 53348049Smckusick tl = mtod(m1, u_long *); 53438420Smckusick tlen = 0; 53538420Smckusick if (putsize) { 53648049Smckusick *tl++ = txdr_unsigned(siz); 53738420Smckusick m1->m_len -= NFSX_UNSIGNED; 53838420Smckusick tlen = NFSX_UNSIGNED; 53938420Smckusick putsize = 0; 54038420Smckusick } 54138420Smckusick if (siz < m1->m_len) { 54238420Smckusick len = nfsm_rndup(siz); 54338420Smckusick xfer = siz; 54438420Smckusick if (xfer < len) 54548049Smckusick *(tl+(xfer>>2)) = 0; 54638420Smckusick } else { 54738420Smckusick xfer = len = m1->m_len; 54838420Smckusick } 54948049Smckusick bcopy(cp, (caddr_t) tl, xfer); 55038420Smckusick m1->m_len = len+tlen; 55138420Smckusick siz -= xfer; 55238420Smckusick cp += xfer; 55338420Smckusick } 55438420Smckusick *mb = m1; 55538420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 55641902Smckusick return (0); 55738420Smckusick } 55838420Smckusick 55938420Smckusick /* 56038420Smckusick * Called once to initialize data structures... 56138420Smckusick */ 56239444Smckusick nfs_init() 56338420Smckusick { 56438420Smckusick register int i; 56552196Smckusick union nqsrvthead *lhp; 56638420Smckusick 56752196Smckusick nfsrtt.pos = 0; 56838420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 56938420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 57038420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 57138420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 57238420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 57338420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 57452196Smckusick rpc_autherr = txdr_unsigned(RPC_AUTHERR); 57552196Smckusick rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 57638420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 57752196Smckusick rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 57838420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 57938420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 58038420Smckusick nfs_true = txdr_unsigned(TRUE); 58138420Smckusick nfs_false = txdr_unsigned(FALSE); 58238420Smckusick /* Loop thru nfs procids */ 58338420Smckusick for (i = 0; i < NFS_NPROCS; i++) 58438420Smckusick nfs_procids[i] = txdr_unsigned(i); 58539345Smckusick /* Ensure async daemons disabled */ 58641902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 58739345Smckusick nfs_iodwant[i] = (struct proc *)0; 58838420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 58938420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 59052979Smckusick nfsrv_init(0); /* Init server data structures */ 59139755Smckusick nfsrv_initcache(); /* Init the server request cache */ 59241902Smckusick 59341902Smckusick /* 59452196Smckusick * Initialize the nqnfs server stuff. 59552196Smckusick */ 59652196Smckusick if (nqnfsstarttime == 0) { 59752196Smckusick nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 59852196Smckusick + nqsrv_clockskew + nqsrv_writeslack; 59952196Smckusick NQLOADNOVRAM(nqnfsstarttime); 60052196Smckusick nqnfs_prog = txdr_unsigned(NQNFS_PROG); 60152196Smckusick nqnfs_vers = txdr_unsigned(NQNFS_VER1); 60252196Smckusick nqthead.th_head[0] = &nqthead; 60352196Smckusick nqthead.th_head[1] = &nqthead; 60455519Smckusick nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash); 60552196Smckusick } 60652196Smckusick 60752196Smckusick /* 60841902Smckusick * Initialize reply list and start timer 60941902Smckusick */ 61041902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 61138420Smckusick nfs_timer(); 61238420Smckusick } 61338420Smckusick 61438420Smckusick /* 61538420Smckusick * Attribute cache routines. 61638420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 61738420Smckusick * that are on the mbuf list 61838420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 61938420Smckusick * error otherwise 62038420Smckusick */ 62138420Smckusick 62238420Smckusick /* 62339444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 62438420Smckusick * the values on the mbuf list and 62538420Smckusick * Iff vap not NULL 62638420Smckusick * copy the attributes to *vaper 62738420Smckusick */ 62839457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 62939457Smckusick struct vnode **vpp; 63038420Smckusick struct mbuf **mdp; 63138420Smckusick caddr_t *dposp; 63238420Smckusick struct vattr *vaper; 63338420Smckusick { 63439457Smckusick register struct vnode *vp = *vpp; 63538420Smckusick register struct vattr *vap; 63638884Smacklem register struct nfsv2_fattr *fp; 63753553Sheideman extern int (**spec_nfsv2nodeop_p)(); 63855519Smckusick register struct nfsnode *np, *nq, **nhpp; 63939494Smckusick register long t1; 64039494Smckusick caddr_t dpos, cp2; 64139494Smckusick int error = 0; 64239494Smckusick struct mbuf *md; 64352196Smckusick enum vtype vtyp; 64452196Smckusick u_short vmode; 64542244Smckusick long rdev; 64639444Smckusick struct timeval mtime; 64739444Smckusick struct vnode *nvp; 64838420Smckusick 64938420Smckusick md = *mdp; 65038420Smckusick dpos = *dposp; 65152196Smckusick t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 65238420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 65338420Smckusick return (error); 65438884Smacklem fp = (struct nfsv2_fattr *)cp2; 65552196Smckusick vtyp = nfstov_type(fp->fa_type); 65652196Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode); 65753384Smckusick if (vtyp == VNON || vtyp == VREG) 65852196Smckusick vtyp = IFTOVT(vmode); 65942244Smckusick rdev = fxdr_unsigned(long, fp->fa_rdev); 66039444Smckusick fxdr_time(&fp->fa_mtime, &mtime); 66139444Smckusick /* 66239444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 66339444Smckusick * n_mtime fields. Check to see if it represents a special 66439444Smckusick * device, and if so, check for a possible alias. Once the 66539444Smckusick * correct vnode has been obtained, fill in the rest of the 66639444Smckusick * information. 66739444Smckusick */ 66838420Smckusick np = VTONFS(vp); 66939444Smckusick if (vp->v_type == VNON) { 67052196Smckusick if (vtyp == VCHR && rdev == 0xffffffff) 67152196Smckusick vp->v_type = vtyp = VFIFO; 67242244Smckusick else 67352196Smckusick vp->v_type = vtyp; 67440295Smckusick if (vp->v_type == VFIFO) { 67540295Smckusick #ifdef FIFO 67653553Sheideman extern int (**fifo_nfsv2nodeop_p)(); 67753553Sheideman vp->v_op = fifo_nfsv2nodeop_p; 67840295Smckusick #else 67940295Smckusick return (EOPNOTSUPP); 68040295Smckusick #endif /* FIFO */ 68140295Smckusick } 68239444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 68353553Sheideman vp->v_op = spec_nfsv2nodeop_p; 68442244Smckusick if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 68539444Smckusick /* 68651984Smckusick * Discard unneeded vnode, but save its nfsnode. 68751984Smckusick */ 68855519Smckusick if (nq = np->n_forw) 68955519Smckusick nq->n_back = np->n_back; 69055519Smckusick *np->n_back = nq; 69151984Smckusick nvp->v_data = vp->v_data; 69251984Smckusick vp->v_data = NULL; 69353553Sheideman vp->v_op = spec_vnodeop_p; 69451984Smckusick vrele(vp); 69551984Smckusick vgone(vp); 69651984Smckusick /* 69739444Smckusick * Reinitialize aliased node. 69839444Smckusick */ 69939444Smckusick np->n_vnode = nvp; 70055519Smckusick nhpp = (struct nfsnode **)nfs_hash(&np->n_fh); 70155519Smckusick if (nq = *nhpp) 70255519Smckusick nq->n_back = &np->n_forw; 70355519Smckusick np->n_forw = nq; 70455519Smckusick np->n_back = nhpp; 70555519Smckusick *nhpp = np; 70651984Smckusick *vpp = vp = nvp; 70739444Smckusick } 70839444Smckusick } 70952196Smckusick if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) 71052196Smckusick np->n_mtime = mtime.tv_sec; 71139444Smckusick } 71238420Smckusick vap = &np->n_vattr; 71352196Smckusick vap->va_type = vtyp; 71452196Smckusick vap->va_mode = (vmode & 07777); 71538884Smacklem vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 71638884Smacklem vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 71738884Smacklem vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 71838884Smacklem vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 71945716Smckusick if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) { 72038884Smacklem np->n_size = vap->va_size; 72153322Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 72245716Smckusick } 72338884Smacklem vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 72442244Smckusick vap->va_rdev = (dev_t)rdev; 72542244Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 72642878Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 72738884Smacklem vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 72854106Smckusick vap->va_atime.ts_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 72954106Smckusick vap->va_atime.ts_nsec = 0; 73039755Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 73154106Smckusick vap->va_mtime.ts_sec = mtime.tv_sec; 73254106Smckusick vap->va_mtime.ts_nsec = mtime.tv_usec * 1000; 73354106Smckusick vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 73454106Smckusick vap->va_ctime.ts_nsec = 0; 73539755Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 73638420Smckusick np->n_attrstamp = time.tv_sec; 73738420Smckusick *dposp = dpos; 73838420Smckusick *mdp = md; 73938884Smacklem if (vaper != NULL) { 74038420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 74138884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 74238884Smacklem vaper->va_size = np->n_size; 74353628Smckusick if (np->n_flag & NCHG) { 74454106Smckusick if (np->n_flag & NACC) { 74554106Smckusick vaper->va_atime.ts_sec = np->n_atim.tv_sec; 74654106Smckusick vaper->va_atime.ts_nsec = 74754106Smckusick np->n_atim.tv_usec * 1000; 74854106Smckusick } 74954106Smckusick if (np->n_flag & NUPD) { 75054106Smckusick vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 75154106Smckusick vaper->va_mtime.ts_nsec = 75254106Smckusick np->n_mtim.tv_usec * 1000; 75354106Smckusick } 75453628Smckusick } 75538884Smacklem } 75638420Smckusick return (0); 75738420Smckusick } 75838420Smckusick 75938420Smckusick /* 76038420Smckusick * Check the time stamp 76138420Smckusick * If the cache is valid, copy contents to *vap and return 0 76238420Smckusick * otherwise return an error 76338420Smckusick */ 76438420Smckusick nfs_getattrcache(vp, vap) 76538420Smckusick register struct vnode *vp; 76638420Smckusick struct vattr *vap; 76738420Smckusick { 76838420Smckusick register struct nfsnode *np; 76938420Smckusick 77038420Smckusick np = VTONFS(vp); 77152196Smckusick if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { 77252196Smckusick if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 77352196Smckusick nfsstats.attrcache_misses++; 77452196Smckusick return (ENOENT); 77552196Smckusick } 77652196Smckusick } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO) { 77738420Smckusick nfsstats.attrcache_misses++; 77838420Smckusick return (ENOENT); 77938420Smckusick } 78052196Smckusick nfsstats.attrcache_hits++; 78152196Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 78252196Smckusick if ((np->n_flag & NMODIFIED) == 0) { 78352196Smckusick np->n_size = vap->va_size; 78453322Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 78552196Smckusick } else if (np->n_size > vap->va_size) 78652196Smckusick vap->va_size = np->n_size; 78753628Smckusick if (np->n_flag & NCHG) { 78854106Smckusick if (np->n_flag & NACC) { 78954106Smckusick vap->va_atime.ts_sec = np->n_atim.tv_sec; 79054106Smckusick vap->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 79154106Smckusick } 79254106Smckusick if (np->n_flag & NUPD) { 79354106Smckusick vap->va_mtime.ts_sec = np->n_mtim.tv_sec; 79454106Smckusick vap->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 79554106Smckusick } 79653628Smckusick } 79752196Smckusick return (0); 79838420Smckusick } 79938420Smckusick 80038420Smckusick /* 80152196Smckusick * Set up nameidata for a lookup() call and do it 80238420Smckusick */ 80352196Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 80438420Smckusick register struct nameidata *ndp; 80538420Smckusick fhandle_t *fhp; 80638420Smckusick int len; 80752196Smckusick struct nfssvc_sock *slp; 80852196Smckusick struct mbuf *nam; 80938420Smckusick struct mbuf **mdp; 81038420Smckusick caddr_t *dposp; 81149739Smckusick struct proc *p; 81238420Smckusick { 81338420Smckusick register int i, rem; 81438420Smckusick register struct mbuf *md; 81549739Smckusick register char *fromcp, *tocp; 81646514Smckusick struct vnode *dp; 81752315Sheideman int error, rdonly; 81852315Sheideman struct componentname *cnp = &ndp->ni_cnd; 81938420Smckusick 82052315Sheideman MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 82149739Smckusick /* 82249739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf 82349739Smckusick * and set the various ndp fields appropriately. 82449739Smckusick */ 82549739Smckusick fromcp = *dposp; 82652315Sheideman tocp = cnp->cn_pnbuf; 82749739Smckusick md = *mdp; 82849739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp; 82952315Sheideman cnp->cn_hash = 0; 83049739Smckusick for (i = 0; i < len; i++) { 83149739Smckusick while (rem == 0) { 83249739Smckusick md = md->m_next; 83349739Smckusick if (md == NULL) { 83449739Smckusick error = EBADRPC; 83549739Smckusick goto out; 83642244Smckusick } 83749739Smckusick fromcp = mtod(md, caddr_t); 83849739Smckusick rem = md->m_len; 83938420Smckusick } 84049739Smckusick if (*fromcp == '\0' || *fromcp == '/') { 84149739Smckusick error = EINVAL; 84249739Smckusick goto out; 84342244Smckusick } 84449739Smckusick if (*fromcp & 0200) 84552315Sheideman if ((*fromcp&0377) == ('/'|0200) || cnp->cn_nameiop != DELETE) { 84649739Smckusick error = EINVAL; 84749739Smckusick goto out; 84849739Smckusick } 84952315Sheideman cnp->cn_hash += (unsigned char)*fromcp; 85049739Smckusick *tocp++ = *fromcp++; 85149739Smckusick rem--; 85249739Smckusick } 85349739Smckusick *tocp = '\0'; 85449739Smckusick *mdp = md; 85549739Smckusick *dposp = fromcp; 85649739Smckusick len = nfsm_rndup(len)-len; 85749739Smckusick if (len > 0) { 85849739Smckusick if (rem >= len) 85949739Smckusick *dposp += len; 86049739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem)) 86149739Smckusick goto out; 86249739Smckusick } 86352315Sheideman ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 86452315Sheideman cnp->cn_nameptr = cnp->cn_pnbuf; 86546514Smckusick /* 86646514Smckusick * Extract and set starting directory. 86746514Smckusick */ 86852315Sheideman if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 86952315Sheideman nam, &rdonly)) 87049739Smckusick goto out; 87138425Smckusick if (dp->v_type != VDIR) { 87241902Smckusick vrele(dp); 87349739Smckusick error = ENOTDIR; 87449739Smckusick goto out; 87538425Smckusick } 87646514Smckusick ndp->ni_startdir = dp; 87752196Smckusick if (rdonly) 87852315Sheideman cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 87952196Smckusick else 88052315Sheideman cnp->cn_flags |= NOCROSSMOUNT; 88139345Smckusick /* 88249739Smckusick * And call lookup() to do the real work 88338420Smckusick */ 88452315Sheideman cnp->cn_proc = p; 88552315Sheideman if (error = lookup(ndp)) 88649739Smckusick goto out; 88749739Smckusick /* 88849739Smckusick * Check for encountering a symbolic link 88949739Smckusick */ 89052315Sheideman if (cnp->cn_flags & ISSYMLINK) { 89152315Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 89249739Smckusick vput(ndp->ni_dvp); 89349739Smckusick else 89449739Smckusick vrele(ndp->ni_dvp); 89549739Smckusick vput(ndp->ni_vp); 89649739Smckusick ndp->ni_vp = NULL; 89749739Smckusick error = EINVAL; 89849739Smckusick goto out; 89949739Smckusick } 90049739Smckusick /* 90149739Smckusick * Check for saved name request 90249739Smckusick */ 90352315Sheideman if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 90452315Sheideman cnp->cn_flags |= HASBUF; 90549739Smckusick return (0); 90649739Smckusick } 90749739Smckusick out: 90852315Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 90938420Smckusick return (error); 91038420Smckusick } 91138420Smckusick 91238420Smckusick /* 91338420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 91438420Smckusick * boundary and only trims off the back end 91538420Smckusick */ 91652196Smckusick void 91738420Smckusick nfsm_adj(mp, len, nul) 91838420Smckusick struct mbuf *mp; 91938420Smckusick register int len; 92038420Smckusick int nul; 92138420Smckusick { 92238420Smckusick register struct mbuf *m; 92338420Smckusick register int count, i; 92438420Smckusick register char *cp; 92538420Smckusick 92638420Smckusick /* 92738420Smckusick * Trim from tail. Scan the mbuf chain, 92838420Smckusick * calculating its length and finding the last mbuf. 92938420Smckusick * If the adjustment only affects this mbuf, then just 93038420Smckusick * adjust and return. Otherwise, rescan and truncate 93138420Smckusick * after the remaining size. 93238420Smckusick */ 93338420Smckusick count = 0; 93438420Smckusick m = mp; 93538420Smckusick for (;;) { 93638420Smckusick count += m->m_len; 93738420Smckusick if (m->m_next == (struct mbuf *)0) 93838420Smckusick break; 93938420Smckusick m = m->m_next; 94038420Smckusick } 94138579Smckusick if (m->m_len > len) { 94238420Smckusick m->m_len -= len; 94338420Smckusick if (nul > 0) { 94438420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 94538420Smckusick for (i = 0; i < nul; i++) 94638420Smckusick *cp++ = '\0'; 94738420Smckusick } 94838420Smckusick return; 94938420Smckusick } 95038420Smckusick count -= len; 95138420Smckusick if (count < 0) 95238420Smckusick count = 0; 95338420Smckusick /* 95438420Smckusick * Correct length for chain is "count". 95538420Smckusick * Find the mbuf with last data, adjust its length, 95638420Smckusick * and toss data from remaining mbufs on chain. 95738420Smckusick */ 95838420Smckusick for (m = mp; m; m = m->m_next) { 95938420Smckusick if (m->m_len >= count) { 96038420Smckusick m->m_len = count; 96138420Smckusick if (nul > 0) { 96238420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 96338420Smckusick for (i = 0; i < nul; i++) 96438420Smckusick *cp++ = '\0'; 96538420Smckusick } 96638420Smckusick break; 96738420Smckusick } 96838420Smckusick count -= m->m_len; 96938420Smckusick } 97038420Smckusick while (m = m->m_next) 97138420Smckusick m->m_len = 0; 97238420Smckusick } 97338420Smckusick 97438420Smckusick /* 97538420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 97638420Smckusick * - look up fsid in mount list (if not found ret error) 97754739Smckusick * - get vp and export rights by calling VFS_FHTOVP() 97854739Smckusick * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 97938420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 98038420Smckusick */ 98152196Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 98238420Smckusick fhandle_t *fhp; 98338420Smckusick int lockflag; 98438420Smckusick struct vnode **vpp; 98538420Smckusick struct ucred *cred; 98652196Smckusick struct nfssvc_sock *slp; 98752196Smckusick struct mbuf *nam; 98852196Smckusick int *rdonlyp; 98938420Smckusick { 99038420Smckusick register struct mount *mp; 99152196Smckusick register struct nfsuid *uidp; 99254739Smckusick struct ucred *credanon; 99354739Smckusick int error, exflags; 99438420Smckusick 99552196Smckusick *vpp = (struct vnode *)0; 99638420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 99738420Smckusick return (ESTALE); 99854739Smckusick if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) 99954739Smckusick return (error); 100052196Smckusick /* 100152196Smckusick * Check/setup credentials. 100252196Smckusick */ 100354739Smckusick if (exflags & MNT_EXKERB) { 100452196Smckusick uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 100552196Smckusick while (uidp) { 100652196Smckusick if (uidp->nu_uid == cred->cr_uid) 100752196Smckusick break; 100852196Smckusick uidp = uidp->nu_hnext; 100945282Smckusick } 101052196Smckusick if (uidp) { 101152196Smckusick if (cred->cr_ref != 1) 101252196Smckusick panic("nsrv fhtovp"); 101352196Smckusick *cred = uidp->nu_cr; 101452196Smckusick } else 101552196Smckusick return (NQNFS_AUTHERR); 101654739Smckusick } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) 101754739Smckusick *cred = *credanon; 101854739Smckusick if (exflags & MNT_EXRDONLY) 101952196Smckusick *rdonlyp = 1; 102045282Smckusick else 102152196Smckusick *rdonlyp = 0; 102252196Smckusick if (!lockflag) 102352196Smckusick VOP_UNLOCK(*vpp); 102452196Smckusick return (0); 102545282Smckusick } 102654988Smckusick 102754988Smckusick /* 102854988Smckusick * This function compares two net addresses by family and returns TRUE 102954988Smckusick * if they are the same host. 103054988Smckusick * If there is any doubt, return FALSE. 103154988Smckusick * The AF_INET family is handled as a special case so that address mbufs 103254988Smckusick * don't need to be saved to store "struct in_addr", which is only 4 bytes. 103354988Smckusick */ 103454988Smckusick netaddr_match(family, haddr, hmask, nam) 103554988Smckusick int family; 103654988Smckusick union nethostaddr *haddr; 103754988Smckusick union nethostaddr *hmask; 103854988Smckusick struct mbuf *nam; 103954988Smckusick { 104054988Smckusick register struct sockaddr_in *inetaddr; 104154988Smckusick #ifdef ISO 104254988Smckusick register struct sockaddr_iso *isoaddr1, *isoaddr2; 104354988Smckusick #endif 104454988Smckusick 104554988Smckusick 104654988Smckusick switch (family) { 104754988Smckusick case AF_INET: 104854988Smckusick inetaddr = mtod(nam, struct sockaddr_in *); 104954988Smckusick if (inetaddr->sin_family != AF_INET) 105054988Smckusick return (0); 105154988Smckusick if (hmask) { 105254988Smckusick if ((inetaddr->sin_addr.s_addr & hmask->had_inetaddr) == 105354988Smckusick (haddr->had_inetaddr & hmask->had_inetaddr)) 105454988Smckusick return (1); 105554988Smckusick } else if (inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 105654988Smckusick return (1); 105754988Smckusick break; 105854988Smckusick #ifdef ISO 105954988Smckusick case AF_ISO: 106054988Smckusick isoaddr1 = mtod(nam, struct sockaddr_iso *); 106154988Smckusick if (isoaddr1->siso_family != AF_ISO) 106254988Smckusick return (0); 106354988Smckusick isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 106454988Smckusick if (isoaddr1->siso_nlen > 0 && 106554988Smckusick isoaddr1->siso_nlen == isoaddr2->siso_nlen && 106654988Smckusick SAME_ISOADDR(isoaddr1, isoaddr2)) 106754988Smckusick return (1); 106854988Smckusick break; 106954988Smckusick #endif /* ISO */ 107054988Smckusick default: 107154988Smckusick break; 107254988Smckusick }; 107354988Smckusick return (0); 107454988Smckusick } 107554988Smckusick 107654988Smckusick /* 107754988Smckusick * Generate a hash code for an iso host address. Used by NETADDRHASH() for 107854988Smckusick * iso addresses. 107954988Smckusick */ 108054988Smckusick iso_addrhash(saddr) 108154988Smckusick struct sockaddr *saddr; 108254988Smckusick { 108354988Smckusick #ifdef ISO 108454988Smckusick register struct sockaddr_iso *siso; 108554988Smckusick register int i, sum; 108654988Smckusick 108754988Smckusick sum = 0; 108854988Smckusick for (i = 0; i < siso->siso_nlen; i++) 108954988Smckusick sum += siso->siso_data[i]; 109054988Smckusick return (sum & (NETHASHSZ - 1)); 109154988Smckusick #else 109254988Smckusick return (0); 109354988Smckusick #endif /* ISO */ 109454988Smckusick } 1095