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*51984Smckusick * @(#)nfs_subs.c 7.43 (Berkeley) 12/16/91 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" 2947573Skarels 3051463Sbostic #include "ufs/ufs/quota.h" 3151463Sbostic #include "ufs/ufs/inode.h" 3247573Skarels 3338420Smckusick #include "rpcv2.h" 3438420Smckusick #include "nfsv2.h" 35*51984Smckusick #include "nfs.h" 3638420Smckusick #include "nfsnode.h" 3738884Smacklem #include "nfsiom.h" 3838420Smckusick #include "xdr_subs.h" 3938420Smckusick #include "nfsm_subs.h" 4045282Smckusick #include "nfscompress.h" 4138420Smckusick 4238420Smckusick #define TRUE 1 4338420Smckusick #define FALSE 0 4438420Smckusick 4538420Smckusick /* 4638420Smckusick * Data items converted to xdr at startup, since they are constant 4738420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 4838420Smckusick */ 4938420Smckusick u_long nfs_procids[NFS_NPROCS]; 5038420Smckusick u_long nfs_xdrneg1; 5138420Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 5238420Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 5338420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 5438420Smckusick /* And other global data */ 5538420Smckusick static u_long *rpc_uidp = (u_long *)0; 5638420Smckusick static u_long nfs_xid = 1; 5738420Smckusick static char *rpc_unixauth; 5838420Smckusick extern long hostid; 5942244Smckusick enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 6041902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 6138884Smacklem extern struct map nfsmap[NFS_MSIZ]; 6241902Smckusick extern struct nfsreq nfsreqh; 6338420Smckusick 6438420Smckusick /* Function ret types */ 6538420Smckusick static char *nfs_unixauth(); 6638420Smckusick 6738420Smckusick /* 6838737Smckusick * Maximum number of groups passed through to NFS server. 6941902Smckusick * According to RFC1057 it should be 16. 7038737Smckusick * For release 3.X systems, the maximum value is 8. 7144987Smckusick * For some other servers, the maximum value is 10. 7238737Smckusick */ 7338737Smckusick int numgrps = 8; 7438737Smckusick 7538737Smckusick /* 7638420Smckusick * Create the header for an rpc request packet 7738420Smckusick * The function nfs_unixauth() creates a unix style authorization string 7838420Smckusick * and returns a ptr to it. 7938420Smckusick * The hsiz is the size of the rest of the nfs request header. 8038420Smckusick * (just used to decide if a cluster is a good idea) 8139494Smckusick * nb: Note that the prog, vers and procid args are already in xdr byte order 8238420Smckusick */ 8339494Smckusick struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 8438420Smckusick u_long prog; 8538420Smckusick u_long vers; 8639494Smckusick u_long procid; 8738420Smckusick struct ucred *cred; 8838420Smckusick int hsiz; 8938420Smckusick caddr_t *bpos; 9038420Smckusick struct mbuf **mb; 9138420Smckusick u_long *retxid; 9238420Smckusick { 9338420Smckusick register struct mbuf *mreq, *m; 9448049Smckusick register u_long *tl; 9538420Smckusick struct mbuf *m1; 9638420Smckusick char *ap; 9738420Smckusick int asiz, siz; 9838420Smckusick 9938420Smckusick NFSMGETHDR(mreq); 10044987Smckusick asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps : 10144987Smckusick (cred->cr_ngroups - 1)) << 2); 10238425Smckusick #ifdef FILLINHOST 10338420Smckusick asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 10438425Smckusick #else 10538425Smckusick asiz += 9*NFSX_UNSIGNED; 10638425Smckusick #endif 10738420Smckusick 10838420Smckusick /* If we need a lot, alloc a cluster ?? */ 10938420Smckusick if ((asiz+hsiz+RPC_SIZ) > MHLEN) 11041902Smckusick MCLGET(mreq, M_WAIT); 11138420Smckusick mreq->m_len = NFSMSIZ(mreq); 11238420Smckusick siz = mreq->m_len; 11338420Smckusick m1 = mreq; 11438420Smckusick /* 11538420Smckusick * Alloc enough mbufs 11638420Smckusick * We do it now to avoid all sleeps after the call to nfs_unixauth() 11738420Smckusick */ 11838420Smckusick while ((asiz+RPC_SIZ) > siz) { 11938420Smckusick MGET(m, M_WAIT, MT_DATA); 12038420Smckusick m1->m_next = m; 12138420Smckusick m->m_len = MLEN; 12238420Smckusick siz += MLEN; 12338420Smckusick m1 = m; 12438420Smckusick } 12548049Smckusick tl = mtod(mreq, u_long *); 12648049Smckusick *tl++ = *retxid = txdr_unsigned(++nfs_xid); 12748049Smckusick *tl++ = rpc_call; 12848049Smckusick *tl++ = rpc_vers; 12948049Smckusick *tl++ = prog; 13048049Smckusick *tl++ = vers; 13148049Smckusick *tl++ = procid; 13238420Smckusick 13338420Smckusick /* Now we can call nfs_unixauth() and copy it in */ 13438420Smckusick ap = nfs_unixauth(cred); 13538420Smckusick m = mreq; 13638420Smckusick siz = m->m_len-RPC_SIZ; 13738420Smckusick if (asiz <= siz) { 13848049Smckusick bcopy(ap, (caddr_t)tl, asiz); 13938420Smckusick m->m_len = asiz+RPC_SIZ; 14038420Smckusick } else { 14148049Smckusick bcopy(ap, (caddr_t)tl, siz); 14238420Smckusick ap += siz; 14338420Smckusick asiz -= siz; 14438420Smckusick while (asiz > 0) { 14538420Smckusick siz = (asiz > MLEN) ? MLEN : asiz; 14638420Smckusick m = m->m_next; 14738420Smckusick bcopy(ap, mtod(m, caddr_t), siz); 14838420Smckusick m->m_len = siz; 14938420Smckusick asiz -= siz; 15038420Smckusick ap += siz; 15138420Smckusick } 15238420Smckusick } 15338420Smckusick 15438420Smckusick /* Finally, return values */ 15538420Smckusick *mb = m; 15638420Smckusick *bpos = mtod(m, caddr_t)+m->m_len; 15738420Smckusick return (mreq); 15838420Smckusick } 15938420Smckusick 16038420Smckusick /* 16138420Smckusick * copies mbuf chain to the uio scatter/gather list 16238420Smckusick */ 16338420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 16438420Smckusick struct mbuf **mrep; 16543353Smckusick register struct uio *uiop; 16638420Smckusick int siz; 16738420Smckusick caddr_t *dpos; 16838420Smckusick { 16943353Smckusick register char *mbufcp, *uiocp; 17038420Smckusick register int xfer, left, len; 17138420Smckusick register struct mbuf *mp; 17238420Smckusick long uiosiz, rem; 17341902Smckusick int error = 0; 17438420Smckusick 17538420Smckusick mp = *mrep; 17638420Smckusick mbufcp = *dpos; 17738420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 17838420Smckusick rem = nfsm_rndup(siz)-siz; 17938420Smckusick while (siz > 0) { 18038420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 18141902Smckusick return (EFBIG); 18238420Smckusick left = uiop->uio_iov->iov_len; 18338420Smckusick uiocp = uiop->uio_iov->iov_base; 18438420Smckusick if (left > siz) 18538420Smckusick left = siz; 18638420Smckusick uiosiz = left; 18738420Smckusick while (left > 0) { 18838420Smckusick while (len == 0) { 18938420Smckusick mp = mp->m_next; 19038420Smckusick if (mp == NULL) 19138420Smckusick return (EBADRPC); 19238420Smckusick mbufcp = mtod(mp, caddr_t); 19338420Smckusick len = mp->m_len; 19438420Smckusick } 19538420Smckusick xfer = (left > len) ? len : left; 19638420Smckusick #ifdef notdef 19738420Smckusick /* Not Yet.. */ 19838420Smckusick if (uiop->uio_iov->iov_op != NULL) 19938420Smckusick (*(uiop->uio_iov->iov_op)) 20038420Smckusick (mbufcp, uiocp, xfer); 20138420Smckusick else 20238420Smckusick #endif 20338420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 20438420Smckusick bcopy(mbufcp, uiocp, xfer); 20538420Smckusick else 20638420Smckusick copyout(mbufcp, uiocp, xfer); 20738420Smckusick left -= xfer; 20838420Smckusick len -= xfer; 20938420Smckusick mbufcp += xfer; 21038420Smckusick uiocp += xfer; 21139585Smckusick uiop->uio_offset += xfer; 21238420Smckusick uiop->uio_resid -= xfer; 21338420Smckusick } 21438420Smckusick if (uiop->uio_iov->iov_len <= siz) { 21538420Smckusick uiop->uio_iovcnt--; 21638420Smckusick uiop->uio_iov++; 21738420Smckusick } else { 21838420Smckusick uiop->uio_iov->iov_base += uiosiz; 21938420Smckusick uiop->uio_iov->iov_len -= uiosiz; 22038420Smckusick } 22138420Smckusick siz -= uiosiz; 22238420Smckusick } 22338420Smckusick *dpos = mbufcp; 22438420Smckusick *mrep = mp; 22541902Smckusick if (rem > 0) { 22641902Smckusick if (len < rem) 22741902Smckusick error = nfs_adv(mrep, dpos, rem, len); 22841902Smckusick else 22941902Smckusick *dpos += rem; 23041902Smckusick } 23141902Smckusick return (error); 23238420Smckusick } 23338420Smckusick 23438420Smckusick /* 23538420Smckusick * copies a uio scatter/gather list to an mbuf chain... 23638420Smckusick */ 23738420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 23838420Smckusick register struct uio *uiop; 23938420Smckusick struct mbuf **mq; 24038420Smckusick int siz; 24138420Smckusick caddr_t *bpos; 24238420Smckusick { 24343353Smckusick register char *uiocp; 24443353Smckusick register struct mbuf *mp, *mp2; 24543353Smckusick register int xfer, left, len; 24643353Smckusick int uiosiz, clflg, rem; 24743353Smckusick char *cp; 24838420Smckusick 24938420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 25038420Smckusick clflg = 1; 25138420Smckusick else 25238420Smckusick clflg = 0; 25338420Smckusick rem = nfsm_rndup(siz)-siz; 25438420Smckusick mp2 = *mq; 25538420Smckusick while (siz > 0) { 25638420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 25741902Smckusick return (EINVAL); 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 MGET(mp, M_WAIT, MT_DATA); 26538420Smckusick if (clflg) 26641902Smckusick MCLGET(mp, M_WAIT); 26738420Smckusick mp->m_len = NFSMSIZ(mp); 26838420Smckusick mp2->m_next = mp; 26938420Smckusick mp2 = mp; 27038420Smckusick xfer = (left > mp->m_len) ? mp->m_len : left; 27138420Smckusick #ifdef notdef 27238420Smckusick /* Not Yet.. */ 27338420Smckusick if (uiop->uio_iov->iov_op != NULL) 27438420Smckusick (*(uiop->uio_iov->iov_op)) 27538420Smckusick (uiocp, mtod(mp, caddr_t), xfer); 27638420Smckusick else 27738420Smckusick #endif 27838420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 27938420Smckusick bcopy(uiocp, mtod(mp, caddr_t), xfer); 28038420Smckusick else 28138420Smckusick copyin(uiocp, mtod(mp, caddr_t), xfer); 28238420Smckusick len = mp->m_len; 28338420Smckusick mp->m_len = xfer; 28438420Smckusick left -= xfer; 28538420Smckusick uiocp += xfer; 28639585Smckusick uiop->uio_offset += xfer; 28738420Smckusick uiop->uio_resid -= xfer; 28838420Smckusick } 28938420Smckusick if (uiop->uio_iov->iov_len <= siz) { 29038420Smckusick uiop->uio_iovcnt--; 29138420Smckusick uiop->uio_iov++; 29238420Smckusick } else { 29338420Smckusick uiop->uio_iov->iov_base += uiosiz; 29438420Smckusick uiop->uio_iov->iov_len -= uiosiz; 29538420Smckusick } 29638420Smckusick siz -= uiosiz; 29738420Smckusick } 29838420Smckusick if (rem > 0) { 29938420Smckusick if (rem > (len-mp->m_len)) { 30038420Smckusick MGET(mp, M_WAIT, MT_DATA); 30138420Smckusick mp->m_len = 0; 30238420Smckusick mp2->m_next = mp; 30338420Smckusick } 30438420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 30538420Smckusick for (left = 0; left < rem; left++) 30638420Smckusick *cp++ = '\0'; 30738420Smckusick mp->m_len += rem; 30838420Smckusick *bpos = cp; 30938420Smckusick } else 31038420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 31138420Smckusick *mq = mp; 31241902Smckusick return (0); 31338420Smckusick } 31438420Smckusick 31538420Smckusick /* 31638420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 31738420Smckusick * pointed to by returned val. 31838420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 31938420Smckusick * This is used by the macros nfsm_disect and nfsm_disecton for tough 32038420Smckusick * cases. (The macros use the vars. dpos and dpos2) 32138420Smckusick */ 32238420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 32338420Smckusick struct mbuf **mdp; 32438420Smckusick caddr_t *dposp; 32538420Smckusick int siz; 32638420Smckusick int left; 32738420Smckusick int updateflg; 32838420Smckusick caddr_t *cp2; 32938420Smckusick { 33038420Smckusick register struct mbuf *mp, *mp2; 33138420Smckusick register int siz2, xfer; 33248049Smckusick register caddr_t tl; 33338420Smckusick 33438420Smckusick mp = *mdp; 33538420Smckusick while (left == 0) { 33638420Smckusick *mdp = mp = mp->m_next; 33738420Smckusick if (mp == NULL) 33841902Smckusick return (EBADRPC); 33938420Smckusick left = mp->m_len; 34038420Smckusick *dposp = mtod(mp, caddr_t); 34138420Smckusick } 34238420Smckusick if (left >= siz) { 34338420Smckusick *cp2 = *dposp; 34438420Smckusick *dposp += siz; 34538420Smckusick } else if (mp->m_next == NULL) { 34641902Smckusick return (EBADRPC); 34741902Smckusick } else if (siz > MHLEN) { 34838420Smckusick panic("nfs S too big"); 34938420Smckusick } else { 35038420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 35138420Smckusick if (updateflg) { 35238420Smckusick NFSMINOFF(mp); 35338420Smckusick } else { 35438420Smckusick MGET(mp2, M_WAIT, MT_DATA); 35538420Smckusick mp2->m_next = mp->m_next; 35638420Smckusick mp->m_next = mp2; 35738420Smckusick mp->m_len -= left; 35838420Smckusick mp = mp2; 35938420Smckusick } 36048049Smckusick *cp2 = tl = mtod(mp, caddr_t); 36148049Smckusick bcopy(*dposp, tl, left); /* Copy what was left */ 36238420Smckusick siz2 = siz-left; 36348049Smckusick tl += left; 36438420Smckusick mp2 = mp->m_next; 36541902Smckusick /* Loop around copying up the siz2 bytes */ 36638420Smckusick while (siz2 > 0) { 36738420Smckusick if (mp2 == NULL) 36838420Smckusick return (EBADRPC); 36938420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 37041902Smckusick if (xfer > 0) { 37148049Smckusick bcopy(mtod(mp2, caddr_t), tl, xfer); 37241902Smckusick NFSMADV(mp2, xfer); 37341902Smckusick mp2->m_len -= xfer; 37448049Smckusick tl += xfer; 37541902Smckusick siz2 -= xfer; 37641902Smckusick } 37738420Smckusick if (siz2 > 0) 37838420Smckusick mp2 = mp2->m_next; 37938420Smckusick } 38038420Smckusick mp->m_len = siz; 38138420Smckusick *mdp = mp2; 38238420Smckusick *dposp = mtod(mp2, caddr_t); 38338420Smckusick } 38439494Smckusick return (0); 38538420Smckusick } 38638420Smckusick 38738420Smckusick /* 38841902Smckusick * Advance the position in the mbuf chain. 38938420Smckusick */ 39038420Smckusick nfs_adv(mdp, dposp, offs, left) 39138420Smckusick struct mbuf **mdp; 39238420Smckusick caddr_t *dposp; 39338420Smckusick int offs; 39438420Smckusick int left; 39538420Smckusick { 39638420Smckusick register struct mbuf *m; 39738420Smckusick register int s; 39838420Smckusick 39938420Smckusick m = *mdp; 40038420Smckusick s = left; 40138420Smckusick while (s < offs) { 40238420Smckusick offs -= s; 40338420Smckusick m = m->m_next; 40438420Smckusick if (m == NULL) 40541902Smckusick return (EBADRPC); 40638420Smckusick s = m->m_len; 40738420Smckusick } 40838420Smckusick *mdp = m; 40938420Smckusick *dposp = mtod(m, caddr_t)+offs; 41041902Smckusick return (0); 41138420Smckusick } 41238420Smckusick 41338420Smckusick /* 41438420Smckusick * Copy a string into mbufs for the hard cases... 41538420Smckusick */ 41638420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 41738420Smckusick struct mbuf **mb; 41838420Smckusick char **bpos; 41938420Smckusick char *cp; 42038420Smckusick long siz; 42138420Smckusick { 42238420Smckusick register struct mbuf *m1, *m2; 42338420Smckusick long left, xfer, len, tlen; 42448049Smckusick u_long *tl; 42538420Smckusick int putsize; 42638420Smckusick 42738420Smckusick putsize = 1; 42838420Smckusick m2 = *mb; 42938420Smckusick left = NFSMSIZ(m2)-m2->m_len; 43038420Smckusick if (left > 0) { 43148049Smckusick tl = ((u_long *)(*bpos)); 43248049Smckusick *tl++ = txdr_unsigned(siz); 43338420Smckusick putsize = 0; 43438420Smckusick left -= NFSX_UNSIGNED; 43538420Smckusick m2->m_len += NFSX_UNSIGNED; 43638420Smckusick if (left > 0) { 43748049Smckusick bcopy(cp, (caddr_t) tl, left); 43838420Smckusick siz -= left; 43938420Smckusick cp += left; 44038420Smckusick m2->m_len += left; 44138420Smckusick left = 0; 44238420Smckusick } 44338420Smckusick } 44438420Smckusick /* Loop arround adding mbufs */ 44538420Smckusick while (siz > 0) { 44638420Smckusick MGET(m1, M_WAIT, MT_DATA); 44738420Smckusick if (siz > MLEN) 44841902Smckusick MCLGET(m1, M_WAIT); 44938420Smckusick m1->m_len = NFSMSIZ(m1); 45038420Smckusick m2->m_next = m1; 45138420Smckusick m2 = m1; 45248049Smckusick tl = mtod(m1, u_long *); 45338420Smckusick tlen = 0; 45438420Smckusick if (putsize) { 45548049Smckusick *tl++ = txdr_unsigned(siz); 45638420Smckusick m1->m_len -= NFSX_UNSIGNED; 45738420Smckusick tlen = NFSX_UNSIGNED; 45838420Smckusick putsize = 0; 45938420Smckusick } 46038420Smckusick if (siz < m1->m_len) { 46138420Smckusick len = nfsm_rndup(siz); 46238420Smckusick xfer = siz; 46338420Smckusick if (xfer < len) 46448049Smckusick *(tl+(xfer>>2)) = 0; 46538420Smckusick } else { 46638420Smckusick xfer = len = m1->m_len; 46738420Smckusick } 46848049Smckusick bcopy(cp, (caddr_t) tl, xfer); 46938420Smckusick m1->m_len = len+tlen; 47038420Smckusick siz -= xfer; 47138420Smckusick cp += xfer; 47238420Smckusick } 47338420Smckusick *mb = m1; 47438420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 47541902Smckusick return (0); 47638420Smckusick } 47738420Smckusick 47838420Smckusick /* 47938420Smckusick * Called once to initialize data structures... 48038420Smckusick */ 48139444Smckusick nfs_init() 48238420Smckusick { 48338420Smckusick register int i; 48438420Smckusick 48538420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 48638420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 48738420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 48838420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 48938420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 49038420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 49138420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 49238420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 49338420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 49438420Smckusick nfs_true = txdr_unsigned(TRUE); 49538420Smckusick nfs_false = txdr_unsigned(FALSE); 49638420Smckusick /* Loop thru nfs procids */ 49738420Smckusick for (i = 0; i < NFS_NPROCS; i++) 49838420Smckusick nfs_procids[i] = txdr_unsigned(i); 49939345Smckusick /* Ensure async daemons disabled */ 50041902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 50139345Smckusick nfs_iodwant[i] = (struct proc *)0; 50238420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 50338420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 50439755Smckusick nfsrv_initcache(); /* Init the server request cache */ 50538884Smacklem rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 50641902Smckusick 50741902Smckusick /* 50841902Smckusick * Initialize reply list and start timer 50941902Smckusick */ 51041902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 51138420Smckusick nfs_timer(); 51238420Smckusick } 51338420Smckusick 51438420Smckusick /* 51538420Smckusick * Fill in the rest of the rpc_unixauth and return it 51638420Smckusick */ 51738420Smckusick static char *nfs_unixauth(cr) 51838420Smckusick register struct ucred *cr; 51938420Smckusick { 52048049Smckusick register u_long *tl; 52138420Smckusick register int i; 52238420Smckusick int ngr; 52338420Smckusick 52438420Smckusick /* Maybe someday there should be a cache of AUTH_SHORT's */ 52548049Smckusick if ((tl = rpc_uidp) == NULL) { 52638425Smckusick #ifdef FILLINHOST 52744987Smckusick i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED); 52838425Smckusick #else 52944987Smckusick i = 25*NFSX_UNSIGNED; 53038425Smckusick #endif 53148049Smckusick MALLOC(tl, u_long *, i, M_TEMP, M_WAITOK); 53248049Smckusick bzero((caddr_t)tl, i); 53348049Smckusick rpc_unixauth = (caddr_t)tl; 53448049Smckusick *tl++ = txdr_unsigned(RPCAUTH_UNIX); 53548049Smckusick tl++; /* Fill in size later */ 53648049Smckusick *tl++ = hostid; 53738425Smckusick #ifdef FILLINHOST 53848049Smckusick *tl++ = txdr_unsigned(hostnamelen); 53938420Smckusick i = nfsm_rndup(hostnamelen); 54048049Smckusick bcopy(hostname, (caddr_t)tl, hostnamelen); 54148049Smckusick tl += (i>>2); 54238425Smckusick #else 54348049Smckusick *tl++ = 0; 54438425Smckusick #endif 54548049Smckusick rpc_uidp = tl; 54638420Smckusick } 54748049Smckusick *tl++ = txdr_unsigned(cr->cr_uid); 54848049Smckusick *tl++ = txdr_unsigned(cr->cr_groups[0]); 54944987Smckusick ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1); 55048049Smckusick *tl++ = txdr_unsigned(ngr); 55144987Smckusick for (i = 1; i <= ngr; i++) 55248049Smckusick *tl++ = txdr_unsigned(cr->cr_groups[i]); 55338420Smckusick /* And add the AUTH_NULL */ 55448049Smckusick *tl++ = 0; 55548049Smckusick *tl = 0; 55648049Smckusick i = (((caddr_t)tl)-rpc_unixauth)-12; 55748049Smckusick tl = (u_long *)(rpc_unixauth+4); 55848049Smckusick *tl = txdr_unsigned(i); 55941902Smckusick return (rpc_unixauth); 56038420Smckusick } 56138420Smckusick 56238420Smckusick /* 56338420Smckusick * Attribute cache routines. 56438420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 56538420Smckusick * that are on the mbuf list 56638420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 56738420Smckusick * error otherwise 56838420Smckusick */ 56938420Smckusick 57038420Smckusick /* 57139444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 57238420Smckusick * the values on the mbuf list and 57338420Smckusick * Iff vap not NULL 57438420Smckusick * copy the attributes to *vaper 57538420Smckusick */ 57639457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 57739457Smckusick struct vnode **vpp; 57838420Smckusick struct mbuf **mdp; 57938420Smckusick caddr_t *dposp; 58038420Smckusick struct vattr *vaper; 58138420Smckusick { 58239457Smckusick register struct vnode *vp = *vpp; 58338420Smckusick register struct vattr *vap; 58438884Smacklem register struct nfsv2_fattr *fp; 585*51984Smckusick extern struct vnodeops spec_nfsv2nodeops, spec_vnodeops; 58639457Smckusick register struct nfsnode *np; 58739494Smckusick register long t1; 58839494Smckusick caddr_t dpos, cp2; 58939494Smckusick int error = 0; 59039494Smckusick struct mbuf *md; 59139444Smckusick enum vtype type; 59246988Smckusick u_short mode; 59342244Smckusick long rdev; 59439444Smckusick struct timeval mtime; 59539444Smckusick struct vnode *nvp; 59638420Smckusick 59738420Smckusick md = *mdp; 59838420Smckusick dpos = *dposp; 59938420Smckusick t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 60038420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 60138420Smckusick return (error); 60238884Smacklem fp = (struct nfsv2_fattr *)cp2; 60339444Smckusick type = nfstov_type(fp->fa_type); 60446988Smckusick mode = fxdr_unsigned(u_short, fp->fa_mode); 60546988Smckusick if (type == VNON) 60646988Smckusick type = IFTOVT(mode); 60742244Smckusick rdev = fxdr_unsigned(long, fp->fa_rdev); 60839444Smckusick fxdr_time(&fp->fa_mtime, &mtime); 60939444Smckusick /* 61039444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 61139444Smckusick * n_mtime fields. Check to see if it represents a special 61239444Smckusick * device, and if so, check for a possible alias. Once the 61339444Smckusick * correct vnode has been obtained, fill in the rest of the 61439444Smckusick * information. 61539444Smckusick */ 61638420Smckusick np = VTONFS(vp); 61739444Smckusick if (vp->v_type == VNON) { 61842244Smckusick if (type == VCHR && rdev == 0xffffffff) 61942244Smckusick vp->v_type = type = VFIFO; 62042244Smckusick else 62142244Smckusick vp->v_type = type; 62240295Smckusick if (vp->v_type == VFIFO) { 62340295Smckusick #ifdef FIFO 62440295Smckusick extern struct vnodeops fifo_nfsv2nodeops; 62540295Smckusick vp->v_op = &fifo_nfsv2nodeops; 62640295Smckusick #else 62740295Smckusick return (EOPNOTSUPP); 62840295Smckusick #endif /* FIFO */ 62940295Smckusick } 63039444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 63139444Smckusick vp->v_op = &spec_nfsv2nodeops; 63242244Smckusick if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 63339444Smckusick /* 634*51984Smckusick * Discard unneeded vnode, but save its nfsnode. 635*51984Smckusick */ 636*51984Smckusick remque(np); 637*51984Smckusick nfs_unlock(vp); 638*51984Smckusick nvp->v_data = vp->v_data; 639*51984Smckusick vp->v_data = NULL; 640*51984Smckusick vp->v_op = &spec_vnodeops; 641*51984Smckusick vrele(vp); 642*51984Smckusick vgone(vp); 643*51984Smckusick /* 64439444Smckusick * Reinitialize aliased node. 64539444Smckusick */ 64639444Smckusick np->n_vnode = nvp; 647*51984Smckusick insque(np, nfs_hash(&np->n_fh)); 64839907Smckusick nfs_lock(nvp); 649*51984Smckusick *vpp = vp = nvp; 65039444Smckusick } 65139444Smckusick } 65239444Smckusick np->n_mtime = mtime.tv_sec; 65339444Smckusick } 65438420Smckusick vap = &np->n_vattr; 65539444Smckusick vap->va_type = type; 65646988Smckusick vap->va_mode = (mode & 07777); 65738884Smacklem vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 65838884Smacklem vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 65938884Smacklem vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 66038884Smacklem vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 66145716Smckusick if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) { 66238884Smacklem np->n_size = vap->va_size; 66345716Smckusick vnode_pager_setsize(vp, np->n_size); 66445716Smckusick } 66540642Smckusick vap->va_size_rsv = 0; 66638884Smacklem vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 66742244Smckusick vap->va_rdev = (dev_t)rdev; 66842244Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 66940642Smckusick vap->va_bytes_rsv = 0; 67042878Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 67138884Smacklem vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 67239755Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 67339755Smckusick vap->va_atime.tv_usec = 0; 67439755Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 67539444Smckusick vap->va_mtime = mtime; 67639755Smckusick vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 67739755Smckusick vap->va_ctime.tv_usec = 0; 67839755Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 67938420Smckusick np->n_attrstamp = time.tv_sec; 68038420Smckusick *dposp = dpos; 68138420Smckusick *mdp = md; 68238884Smacklem if (vaper != NULL) { 68338420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 68438884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 68538884Smacklem vaper->va_size = np->n_size; 68638884Smacklem } 68738420Smckusick return (0); 68838420Smckusick } 68938420Smckusick 69038420Smckusick /* 69138420Smckusick * Check the time stamp 69238420Smckusick * If the cache is valid, copy contents to *vap and return 0 69338420Smckusick * otherwise return an error 69438420Smckusick */ 69538420Smckusick nfs_getattrcache(vp, vap) 69638420Smckusick register struct vnode *vp; 69738420Smckusick struct vattr *vap; 69838420Smckusick { 69938420Smckusick register struct nfsnode *np; 70038420Smckusick 70138420Smckusick np = VTONFS(vp); 70238420Smckusick if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 70338420Smckusick nfsstats.attrcache_hits++; 70438420Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 70545716Smckusick if ((np->n_flag & NMODIFIED) == 0) { 70639361Smckusick np->n_size = vap->va_size; 70745716Smckusick vnode_pager_setsize(vp, np->n_size); 70845716Smckusick } else if (np->n_size > vap->va_size) 70938884Smacklem vap->va_size = np->n_size; 71038420Smckusick return (0); 71138420Smckusick } else { 71238420Smckusick nfsstats.attrcache_misses++; 71338420Smckusick return (ENOENT); 71438420Smckusick } 71538420Smckusick } 71638420Smckusick 71738420Smckusick /* 71841902Smckusick * Set up nameidata for a namei() call and do it 71938420Smckusick */ 72049739Smckusick nfs_namei(ndp, fhp, len, mdp, dposp, p) 72138420Smckusick register struct nameidata *ndp; 72238420Smckusick fhandle_t *fhp; 72338420Smckusick int len; 72438420Smckusick struct mbuf **mdp; 72538420Smckusick caddr_t *dposp; 72649739Smckusick struct proc *p; 72738420Smckusick { 72838420Smckusick register int i, rem; 72938420Smckusick register struct mbuf *md; 73049739Smckusick register char *fromcp, *tocp; 73146514Smckusick struct vnode *dp; 73238420Smckusick int flag; 73341902Smckusick int error; 73438420Smckusick 73549739Smckusick flag = ndp->ni_nameiop & OPMASK; 73649739Smckusick MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 73749739Smckusick /* 73849739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf 73949739Smckusick * and set the various ndp fields appropriately. 74049739Smckusick */ 74149739Smckusick fromcp = *dposp; 74249739Smckusick tocp = ndp->ni_pnbuf; 74349739Smckusick md = *mdp; 74449739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp; 74549739Smckusick ndp->ni_hash = 0; 74649739Smckusick for (i = 0; i < len; i++) { 74749739Smckusick while (rem == 0) { 74849739Smckusick md = md->m_next; 74949739Smckusick if (md == NULL) { 75049739Smckusick error = EBADRPC; 75149739Smckusick goto out; 75242244Smckusick } 75349739Smckusick fromcp = mtod(md, caddr_t); 75449739Smckusick rem = md->m_len; 75538420Smckusick } 75649739Smckusick if (*fromcp == '\0' || *fromcp == '/') { 75749739Smckusick error = EINVAL; 75849739Smckusick goto out; 75942244Smckusick } 76049739Smckusick if (*fromcp & 0200) 76149739Smckusick if ((*fromcp&0377) == ('/'|0200) || flag != DELETE) { 76249739Smckusick error = EINVAL; 76349739Smckusick goto out; 76449739Smckusick } 76549739Smckusick ndp->ni_hash += (unsigned char)*fromcp; 76649739Smckusick *tocp++ = *fromcp++; 76749739Smckusick rem--; 76849739Smckusick } 76949739Smckusick *tocp = '\0'; 77049739Smckusick *mdp = md; 77149739Smckusick *dposp = fromcp; 77249739Smckusick len = nfsm_rndup(len)-len; 77349739Smckusick if (len > 0) { 77449739Smckusick if (rem >= len) 77549739Smckusick *dposp += len; 77649739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem)) 77749739Smckusick goto out; 77849739Smckusick } 77949739Smckusick ndp->ni_pathlen = tocp - ndp->ni_pnbuf; 78049739Smckusick ndp->ni_ptr = ndp->ni_pnbuf; 78146514Smckusick /* 78246514Smckusick * Extract and set starting directory. 78346514Smckusick */ 78441902Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 78549739Smckusick goto out; 78638425Smckusick if (dp->v_type != VDIR) { 78741902Smckusick vrele(dp); 78849739Smckusick error = ENOTDIR; 78949739Smckusick goto out; 79038425Smckusick } 79146514Smckusick ndp->ni_startdir = dp; 79249739Smckusick ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE); 79339345Smckusick /* 79449739Smckusick * And call lookup() to do the real work 79538420Smckusick */ 79649739Smckusick if (error = lookup(ndp, p)) 79749739Smckusick goto out; 79849739Smckusick /* 79949739Smckusick * Check for encountering a symbolic link 80049739Smckusick */ 80149739Smckusick if (ndp->ni_more) { 80249739Smckusick if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1) 80349739Smckusick vput(ndp->ni_dvp); 80449739Smckusick else 80549739Smckusick vrele(ndp->ni_dvp); 80649739Smckusick vput(ndp->ni_vp); 80749739Smckusick ndp->ni_vp = NULL; 80849739Smckusick error = EINVAL; 80949739Smckusick goto out; 81049739Smckusick } 81149739Smckusick /* 81249739Smckusick * Check for saved name request 81349739Smckusick */ 81449739Smckusick if (ndp->ni_nameiop & (SAVENAME | SAVESTART)) { 81549739Smckusick ndp->ni_nameiop |= HASBUF; 81649739Smckusick return (0); 81749739Smckusick } 81849739Smckusick out: 81949739Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 82038420Smckusick return (error); 82138420Smckusick } 82238420Smckusick 82338420Smckusick /* 82438420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 82538420Smckusick * boundary and only trims off the back end 82638420Smckusick */ 82738420Smckusick nfsm_adj(mp, len, nul) 82838420Smckusick struct mbuf *mp; 82938420Smckusick register int len; 83038420Smckusick int nul; 83138420Smckusick { 83238420Smckusick register struct mbuf *m; 83338420Smckusick register int count, i; 83438420Smckusick register char *cp; 83538420Smckusick 83638420Smckusick /* 83738420Smckusick * Trim from tail. Scan the mbuf chain, 83838420Smckusick * calculating its length and finding the last mbuf. 83938420Smckusick * If the adjustment only affects this mbuf, then just 84038420Smckusick * adjust and return. Otherwise, rescan and truncate 84138420Smckusick * after the remaining size. 84238420Smckusick */ 84338420Smckusick count = 0; 84438420Smckusick m = mp; 84538420Smckusick for (;;) { 84638420Smckusick count += m->m_len; 84738420Smckusick if (m->m_next == (struct mbuf *)0) 84838420Smckusick break; 84938420Smckusick m = m->m_next; 85038420Smckusick } 85138579Smckusick if (m->m_len > len) { 85238420Smckusick m->m_len -= len; 85338420Smckusick if (nul > 0) { 85438420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 85538420Smckusick for (i = 0; i < nul; i++) 85638420Smckusick *cp++ = '\0'; 85738420Smckusick } 85838420Smckusick return; 85938420Smckusick } 86038420Smckusick count -= len; 86138420Smckusick if (count < 0) 86238420Smckusick count = 0; 86338420Smckusick /* 86438420Smckusick * Correct length for chain is "count". 86538420Smckusick * Find the mbuf with last data, adjust its length, 86638420Smckusick * and toss data from remaining mbufs on chain. 86738420Smckusick */ 86838420Smckusick for (m = mp; m; m = m->m_next) { 86938420Smckusick if (m->m_len >= count) { 87038420Smckusick m->m_len = count; 87138420Smckusick if (nul > 0) { 87238420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 87338420Smckusick for (i = 0; i < nul; i++) 87438420Smckusick *cp++ = '\0'; 87538420Smckusick } 87638420Smckusick break; 87738420Smckusick } 87838420Smckusick count -= m->m_len; 87938420Smckusick } 88038420Smckusick while (m = m->m_next) 88138420Smckusick m->m_len = 0; 88238420Smckusick } 88338420Smckusick 88438420Smckusick /* 88538420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 88638420Smckusick * - look up fsid in mount list (if not found ret error) 88738420Smckusick * - check that it is exported 88838420Smckusick * - get vp by calling VFS_FHTOVP() macro 88938420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 89041902Smckusick * - if cred->cr_uid == 0 set it to m_exroot 89138420Smckusick */ 89238420Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred) 89338420Smckusick fhandle_t *fhp; 89438420Smckusick int lockflag; 89538420Smckusick struct vnode **vpp; 89638420Smckusick struct ucred *cred; 89738420Smckusick { 89838420Smckusick register struct mount *mp; 89938420Smckusick 90038420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 90138420Smckusick return (ESTALE); 90241398Smckusick if ((mp->mnt_flag & MNT_EXPORTED) == 0) 90338420Smckusick return (EACCES); 90438420Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 90538420Smckusick return (ESTALE); 90638420Smckusick if (cred->cr_uid == 0) 90741398Smckusick cred->cr_uid = mp->mnt_exroot; 90838420Smckusick if (!lockflag) 90938420Smckusick VOP_UNLOCK(*vpp); 91038420Smckusick return (0); 91138420Smckusick } 91245282Smckusick 91345282Smckusick /* 91445282Smckusick * These two functions implement nfs rpc compression. 91545282Smckusick * The algorithm is a trivial run length encoding of '\0' bytes. The high 91645282Smckusick * order nibble of hex "e" is or'd with the number of zeroes - 2 in four 91745282Smckusick * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e" 91845282Smckusick * is byte stuffed. 91945282Smckusick * The compressed data is padded with 0x0 bytes to an even multiple of 92045282Smckusick * 4 bytes in length to avoid any weird long pointer alignments. 92145282Smckusick * If compression/uncompression is unsuccessful, the original mbuf list 92245282Smckusick * is returned. 92345282Smckusick * The first four bytes (the XID) are left uncompressed and the fifth 92445282Smckusick * byte is set to 0x1 for request and 0x2 for reply. 92545282Smckusick * An uncompressed RPC will always have the fifth byte == 0x0. 92645282Smckusick */ 92745282Smckusick struct mbuf * 92845282Smckusick nfs_compress(m0) 92945282Smckusick struct mbuf *m0; 93045282Smckusick { 93145282Smckusick register u_char ch, nextch; 93245282Smckusick register int i, rlelast; 93345282Smckusick register u_char *ip, *op; 93445282Smckusick register int ileft, oleft, noteof; 93545282Smckusick register struct mbuf *m, *om; 93645282Smckusick struct mbuf **mp, *retm; 93745282Smckusick int olen, clget; 93845282Smckusick 93945282Smckusick i = rlelast = 0; 94045282Smckusick noteof = 1; 94145282Smckusick m = m0; 94245282Smckusick if (m->m_len < 12) 94345282Smckusick return (m0); 94445282Smckusick if (m->m_pkthdr.len >= MINCLSIZE) 94545282Smckusick clget = 1; 94645282Smckusick else 94745282Smckusick clget = 0; 94845282Smckusick ileft = m->m_len - 9; 94945282Smckusick ip = mtod(m, u_char *); 95045288Smckusick MGETHDR(om, M_WAIT, MT_DATA); 95145282Smckusick if (clget) 95245282Smckusick MCLGET(om, M_WAIT); 95345282Smckusick retm = om; 95445282Smckusick mp = &om->m_next; 95545282Smckusick olen = om->m_len = 5; 95645282Smckusick oleft = M_TRAILINGSPACE(om); 95745282Smckusick op = mtod(om, u_char *); 95845298Smckusick *((u_long *)op) = *((u_long *)ip); 95945282Smckusick ip += 7; 96045282Smckusick op += 4; 96145282Smckusick *op++ = *ip++ + 1; 96245282Smckusick nextch = *ip++; 96345282Smckusick while (noteof) { 96445282Smckusick ch = nextch; 96545282Smckusick if (ileft == 0) { 96645282Smckusick do { 96745282Smckusick m = m->m_next; 96845282Smckusick } while (m && m->m_len == 0); 96945282Smckusick if (m) { 97045282Smckusick ileft = m->m_len; 97145282Smckusick ip = mtod(m, u_char *); 97245282Smckusick } else { 97345282Smckusick noteof = 0; 97445282Smckusick nextch = 0x1; 97545282Smckusick goto doit; 97645282Smckusick } 97745282Smckusick } 97845282Smckusick nextch = *ip++; 97945282Smckusick ileft--; 98045282Smckusick doit: 98145282Smckusick if (ch == '\0') { 98245282Smckusick if (++i == NFSC_MAX || nextch != '\0') { 98345282Smckusick if (i < 2) { 98445282Smckusick nfscput('\0'); 98545282Smckusick } else { 98645282Smckusick if (rlelast == i) { 98745282Smckusick nfscput('\0'); 98845282Smckusick i--; 98945282Smckusick } 99045282Smckusick if (NFSCRLE(i) == (nextch & 0xff)) { 99145282Smckusick i--; 99245282Smckusick if (i < 2) { 99345282Smckusick nfscput('\0'); 99445282Smckusick } else { 99545282Smckusick nfscput(NFSCRLE(i)); 99645282Smckusick } 99745282Smckusick nfscput('\0'); 99845282Smckusick rlelast = 0; 99945282Smckusick } else { 100045282Smckusick nfscput(NFSCRLE(i)); 100145282Smckusick rlelast = i; 100245282Smckusick } 100345282Smckusick } 100445282Smckusick i = 0; 100545282Smckusick } 100645282Smckusick } else { 100745282Smckusick if ((ch & NFSCRL) == NFSCRL) { 100845282Smckusick nfscput(ch); 100945282Smckusick } 101045282Smckusick nfscput(ch); 101145282Smckusick i = rlelast = 0; 101245282Smckusick } 101345282Smckusick } 101445282Smckusick if (olen < m0->m_pkthdr.len) { 101545282Smckusick m_freem(m0); 101645282Smckusick if (i = (olen & 0x3)) { 101745282Smckusick i = 4 - i; 101845298Smckusick while (i-- > 0) { 101945282Smckusick nfscput('\0'); 102045298Smckusick } 102145282Smckusick } 102245282Smckusick retm->m_pkthdr.len = olen; 102345298Smckusick retm->m_pkthdr.rcvif = (struct ifnet *)0; 102445282Smckusick return (retm); 102545282Smckusick } else { 102645282Smckusick m_freem(retm); 102745282Smckusick return (m0); 102845282Smckusick } 102945282Smckusick } 103045282Smckusick 103145282Smckusick struct mbuf * 103245282Smckusick nfs_uncompress(m0) 103345282Smckusick struct mbuf *m0; 103445282Smckusick { 103545282Smckusick register u_char cp, nextcp, *ip, *op; 103645282Smckusick register struct mbuf *m, *om; 103745282Smckusick struct mbuf *retm, **mp; 103845282Smckusick int i, j, noteof, clget, ileft, oleft, olen; 103945282Smckusick 104045282Smckusick m = m0; 104145298Smckusick i = 0; 104245298Smckusick while (m && i < MINCLSIZE) { 104345298Smckusick i += m->m_len; 104445298Smckusick m = m->m_next; 104545298Smckusick } 104645298Smckusick if (i < 6) 104745282Smckusick return (m0); 104845298Smckusick if (i >= MINCLSIZE) 104945282Smckusick clget = 1; 105045282Smckusick else 105145282Smckusick clget = 0; 105245298Smckusick m = m0; 105345298Smckusick MGET(om, M_WAIT, MT_DATA); 105445282Smckusick if (clget) 105545282Smckusick MCLGET(om, M_WAIT); 105645282Smckusick olen = om->m_len = 8; 105745282Smckusick oleft = M_TRAILINGSPACE(om); 105845282Smckusick op = mtod(om, u_char *); 105945282Smckusick retm = om; 106045282Smckusick mp = &om->m_next; 106145282Smckusick if (m->m_len >= 6) { 106245282Smckusick ileft = m->m_len - 6; 106345282Smckusick ip = mtod(m, u_char *); 106445282Smckusick *((u_long *)op) = *((u_long *)ip); 106545282Smckusick bzero(op + 4, 3); 106645282Smckusick ip += 4; 106745282Smckusick op += 7; 106845282Smckusick if (*ip == '\0') { 106945282Smckusick m_freem(om); 107045282Smckusick return (m0); 107145282Smckusick } 107245282Smckusick *op++ = *ip++ - 1; 107345282Smckusick cp = *ip++; 107445282Smckusick } else { 107545282Smckusick ileft = m->m_len; 107645282Smckusick ip = mtod(m, u_char *); 107745282Smckusick nfscget(*op++); 107845282Smckusick nfscget(*op++); 107945282Smckusick nfscget(*op++); 108045282Smckusick nfscget(*op++); 108145282Smckusick bzero(op, 3); 108245282Smckusick op += 3; 108345282Smckusick nfscget(*op); 108445282Smckusick if (*op == '\0') { 108545282Smckusick m_freem(om); 108645282Smckusick return (m0); 108745282Smckusick } 108845282Smckusick (*op)--; 108945282Smckusick op++; 109045282Smckusick nfscget(cp); 109145282Smckusick } 109245282Smckusick noteof = 1; 109345282Smckusick while (noteof) { 109445282Smckusick if ((cp & NFSCRL) == NFSCRL) { 109545282Smckusick nfscget(nextcp); 109645282Smckusick if (cp == nextcp) { 109745282Smckusick nfscput(cp); 109845282Smckusick goto readit; 109945282Smckusick } else { 110045282Smckusick i = (cp & 0xf) + 2; 110145282Smckusick for (j = 0; j < i; j++) { 110245282Smckusick nfscput('\0'); 110345282Smckusick } 110445282Smckusick cp = nextcp; 110545282Smckusick } 110645282Smckusick } else { 110745282Smckusick nfscput(cp); 110845282Smckusick readit: 110945282Smckusick nfscget(cp); 111045282Smckusick } 111145282Smckusick } 111245282Smckusick m_freem(m0); 111345298Smckusick if (i = (olen & 0x3)) 111445282Smckusick om->m_len -= i; 111545282Smckusick return (retm); 111645282Smckusick } 1117