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*45921Smckusick * @(#)nfs_subs.c 7.35 (Berkeley) 01/10/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 "user.h" 2039345Smckusick #include "proc.h" 21*45921Smckusick #include "filedesc.h" 2240136Smckusick #include "systm.h" 2340136Smckusick #include "kernel.h" 2438420Smckusick #include "mount.h" 2538420Smckusick #include "file.h" 2638420Smckusick #include "vnode.h" 2740136Smckusick #include "mbuf.h" 2840136Smckusick #include "errno.h" 2938884Smacklem #include "map.h" 3038420Smckusick #include "rpcv2.h" 3138420Smckusick #include "nfsv2.h" 3238420Smckusick #include "nfsnode.h" 3338420Smckusick #include "nfs.h" 3438884Smacklem #include "nfsiom.h" 3538420Smckusick #include "xdr_subs.h" 3638420Smckusick #include "nfsm_subs.h" 3745282Smckusick #include "nfscompress.h" 3838420Smckusick 3938420Smckusick #define TRUE 1 4038420Smckusick #define FALSE 0 4138420Smckusick 4238420Smckusick /* 4338420Smckusick * Data items converted to xdr at startup, since they are constant 4438420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 4538420Smckusick */ 4638420Smckusick u_long nfs_procids[NFS_NPROCS]; 4738420Smckusick u_long nfs_xdrneg1; 4838420Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 4938420Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 5038420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 5138420Smckusick /* And other global data */ 5238420Smckusick static u_long *rpc_uidp = (u_long *)0; 5338420Smckusick static u_long nfs_xid = 1; 5438420Smckusick static char *rpc_unixauth; 5538420Smckusick extern long hostid; 5642244Smckusick enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 5741902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 5838884Smacklem extern struct map nfsmap[NFS_MSIZ]; 5941902Smckusick extern struct nfsreq nfsreqh; 6038420Smckusick 6138420Smckusick /* Function ret types */ 6238420Smckusick static char *nfs_unixauth(); 6338420Smckusick 6438420Smckusick /* 6538737Smckusick * Maximum number of groups passed through to NFS server. 6641902Smckusick * According to RFC1057 it should be 16. 6738737Smckusick * For release 3.X systems, the maximum value is 8. 6844987Smckusick * For some other servers, the maximum value is 10. 6938737Smckusick */ 7038737Smckusick int numgrps = 8; 7138737Smckusick 7238737Smckusick /* 7338420Smckusick * Create the header for an rpc request packet 7438420Smckusick * The function nfs_unixauth() creates a unix style authorization string 7538420Smckusick * and returns a ptr to it. 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) 7839494Smckusick * nb: Note that the prog, vers and procid args are already in xdr byte order 7938420Smckusick */ 8039494Smckusick struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 8138420Smckusick u_long prog; 8238420Smckusick u_long vers; 8339494Smckusick u_long procid; 8438420Smckusick struct ucred *cred; 8538420Smckusick int hsiz; 8638420Smckusick caddr_t *bpos; 8738420Smckusick struct mbuf **mb; 8838420Smckusick u_long *retxid; 8938420Smckusick { 9038420Smckusick register struct mbuf *mreq, *m; 9138420Smckusick register u_long *p; 9238420Smckusick struct mbuf *m1; 9338420Smckusick char *ap; 9438420Smckusick int asiz, siz; 9538420Smckusick 9638420Smckusick NFSMGETHDR(mreq); 9744987Smckusick asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps : 9844987Smckusick (cred->cr_ngroups - 1)) << 2); 9938425Smckusick #ifdef FILLINHOST 10038420Smckusick asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 10138425Smckusick #else 10238425Smckusick asiz += 9*NFSX_UNSIGNED; 10338425Smckusick #endif 10438420Smckusick 10538420Smckusick /* If we need a lot, alloc a cluster ?? */ 10638420Smckusick if ((asiz+hsiz+RPC_SIZ) > MHLEN) 10741902Smckusick MCLGET(mreq, M_WAIT); 10838420Smckusick mreq->m_len = NFSMSIZ(mreq); 10938420Smckusick siz = mreq->m_len; 11038420Smckusick m1 = mreq; 11138420Smckusick /* 11238420Smckusick * Alloc enough mbufs 11338420Smckusick * We do it now to avoid all sleeps after the call to nfs_unixauth() 11438420Smckusick */ 11538420Smckusick while ((asiz+RPC_SIZ) > siz) { 11638420Smckusick MGET(m, M_WAIT, MT_DATA); 11738420Smckusick m1->m_next = m; 11838420Smckusick m->m_len = MLEN; 11938420Smckusick siz += MLEN; 12038420Smckusick m1 = m; 12138420Smckusick } 12238420Smckusick p = mtod(mreq, u_long *); 12338420Smckusick *p++ = *retxid = txdr_unsigned(++nfs_xid); 12438420Smckusick *p++ = rpc_call; 12538420Smckusick *p++ = rpc_vers; 12638420Smckusick *p++ = prog; 12738420Smckusick *p++ = vers; 12839494Smckusick *p++ = procid; 12938420Smckusick 13038420Smckusick /* Now we can call nfs_unixauth() and copy it in */ 13138420Smckusick ap = nfs_unixauth(cred); 13238420Smckusick m = mreq; 13338420Smckusick siz = m->m_len-RPC_SIZ; 13438420Smckusick if (asiz <= siz) { 13538420Smckusick bcopy(ap, (caddr_t)p, asiz); 13638420Smckusick m->m_len = asiz+RPC_SIZ; 13738420Smckusick } else { 13838420Smckusick bcopy(ap, (caddr_t)p, siz); 13938420Smckusick ap += siz; 14038420Smckusick asiz -= siz; 14138420Smckusick while (asiz > 0) { 14238420Smckusick siz = (asiz > MLEN) ? MLEN : asiz; 14338420Smckusick m = m->m_next; 14438420Smckusick bcopy(ap, mtod(m, caddr_t), siz); 14538420Smckusick m->m_len = siz; 14638420Smckusick asiz -= siz; 14738420Smckusick ap += siz; 14838420Smckusick } 14938420Smckusick } 15038420Smckusick 15138420Smckusick /* Finally, return values */ 15238420Smckusick *mb = m; 15338420Smckusick *bpos = mtod(m, caddr_t)+m->m_len; 15438420Smckusick return (mreq); 15538420Smckusick } 15638420Smckusick 15738420Smckusick /* 15838420Smckusick * copies mbuf chain to the uio scatter/gather list 15938420Smckusick */ 16038420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 16138420Smckusick struct mbuf **mrep; 16243353Smckusick register struct uio *uiop; 16338420Smckusick int siz; 16438420Smckusick caddr_t *dpos; 16538420Smckusick { 16643353Smckusick register char *mbufcp, *uiocp; 16738420Smckusick register int xfer, left, len; 16838420Smckusick register struct mbuf *mp; 16938420Smckusick long uiosiz, rem; 17041902Smckusick int error = 0; 17138420Smckusick 17238420Smckusick mp = *mrep; 17338420Smckusick mbufcp = *dpos; 17438420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 17538420Smckusick rem = nfsm_rndup(siz)-siz; 17638420Smckusick while (siz > 0) { 17738420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 17841902Smckusick return (EFBIG); 17938420Smckusick left = uiop->uio_iov->iov_len; 18038420Smckusick uiocp = uiop->uio_iov->iov_base; 18138420Smckusick if (left > siz) 18238420Smckusick left = siz; 18338420Smckusick uiosiz = left; 18438420Smckusick while (left > 0) { 18538420Smckusick while (len == 0) { 18638420Smckusick mp = mp->m_next; 18738420Smckusick if (mp == NULL) 18838420Smckusick return (EBADRPC); 18938420Smckusick mbufcp = mtod(mp, caddr_t); 19038420Smckusick len = mp->m_len; 19138420Smckusick } 19238420Smckusick xfer = (left > len) ? len : left; 19338420Smckusick #ifdef notdef 19438420Smckusick /* Not Yet.. */ 19538420Smckusick if (uiop->uio_iov->iov_op != NULL) 19638420Smckusick (*(uiop->uio_iov->iov_op)) 19738420Smckusick (mbufcp, uiocp, xfer); 19838420Smckusick else 19938420Smckusick #endif 20038420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 20138420Smckusick bcopy(mbufcp, uiocp, xfer); 20238420Smckusick else 20338420Smckusick copyout(mbufcp, uiocp, xfer); 20438420Smckusick left -= xfer; 20538420Smckusick len -= xfer; 20638420Smckusick mbufcp += xfer; 20738420Smckusick uiocp += xfer; 20839585Smckusick uiop->uio_offset += xfer; 20938420Smckusick uiop->uio_resid -= xfer; 21038420Smckusick } 21138420Smckusick if (uiop->uio_iov->iov_len <= siz) { 21238420Smckusick uiop->uio_iovcnt--; 21338420Smckusick uiop->uio_iov++; 21438420Smckusick } else { 21538420Smckusick uiop->uio_iov->iov_base += uiosiz; 21638420Smckusick uiop->uio_iov->iov_len -= uiosiz; 21738420Smckusick } 21838420Smckusick siz -= uiosiz; 21938420Smckusick } 22038420Smckusick *dpos = mbufcp; 22138420Smckusick *mrep = mp; 22241902Smckusick if (rem > 0) { 22341902Smckusick if (len < rem) 22441902Smckusick error = nfs_adv(mrep, dpos, rem, len); 22541902Smckusick else 22641902Smckusick *dpos += rem; 22741902Smckusick } 22841902Smckusick return (error); 22938420Smckusick } 23038420Smckusick 23138420Smckusick /* 23238420Smckusick * copies a uio scatter/gather list to an mbuf chain... 23338420Smckusick */ 23438420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 23538420Smckusick register struct uio *uiop; 23638420Smckusick struct mbuf **mq; 23738420Smckusick int siz; 23838420Smckusick caddr_t *bpos; 23938420Smckusick { 24043353Smckusick register char *uiocp; 24143353Smckusick register struct mbuf *mp, *mp2; 24243353Smckusick register int xfer, left, len; 24343353Smckusick int uiosiz, clflg, rem; 24443353Smckusick char *cp; 24538420Smckusick 24638420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 24738420Smckusick clflg = 1; 24838420Smckusick else 24938420Smckusick clflg = 0; 25038420Smckusick rem = nfsm_rndup(siz)-siz; 25138420Smckusick mp2 = *mq; 25238420Smckusick while (siz > 0) { 25338420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 25441902Smckusick return (EINVAL); 25538420Smckusick left = uiop->uio_iov->iov_len; 25638420Smckusick uiocp = uiop->uio_iov->iov_base; 25738420Smckusick if (left > siz) 25838420Smckusick left = siz; 25938420Smckusick uiosiz = left; 26038420Smckusick while (left > 0) { 26138420Smckusick MGET(mp, M_WAIT, MT_DATA); 26238420Smckusick if (clflg) 26341902Smckusick MCLGET(mp, M_WAIT); 26438420Smckusick mp->m_len = NFSMSIZ(mp); 26538420Smckusick mp2->m_next = mp; 26638420Smckusick mp2 = mp; 26738420Smckusick xfer = (left > mp->m_len) ? mp->m_len : left; 26838420Smckusick #ifdef notdef 26938420Smckusick /* Not Yet.. */ 27038420Smckusick if (uiop->uio_iov->iov_op != NULL) 27138420Smckusick (*(uiop->uio_iov->iov_op)) 27238420Smckusick (uiocp, mtod(mp, caddr_t), xfer); 27338420Smckusick else 27438420Smckusick #endif 27538420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 27638420Smckusick bcopy(uiocp, mtod(mp, caddr_t), xfer); 27738420Smckusick else 27838420Smckusick copyin(uiocp, mtod(mp, caddr_t), xfer); 27938420Smckusick len = mp->m_len; 28038420Smckusick mp->m_len = xfer; 28138420Smckusick left -= xfer; 28238420Smckusick uiocp += xfer; 28339585Smckusick uiop->uio_offset += xfer; 28438420Smckusick uiop->uio_resid -= xfer; 28538420Smckusick } 28638420Smckusick if (uiop->uio_iov->iov_len <= siz) { 28738420Smckusick uiop->uio_iovcnt--; 28838420Smckusick uiop->uio_iov++; 28938420Smckusick } else { 29038420Smckusick uiop->uio_iov->iov_base += uiosiz; 29138420Smckusick uiop->uio_iov->iov_len -= uiosiz; 29238420Smckusick } 29338420Smckusick siz -= uiosiz; 29438420Smckusick } 29538420Smckusick if (rem > 0) { 29638420Smckusick if (rem > (len-mp->m_len)) { 29738420Smckusick MGET(mp, M_WAIT, MT_DATA); 29838420Smckusick mp->m_len = 0; 29938420Smckusick mp2->m_next = mp; 30038420Smckusick } 30138420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 30238420Smckusick for (left = 0; left < rem; left++) 30338420Smckusick *cp++ = '\0'; 30438420Smckusick mp->m_len += rem; 30538420Smckusick *bpos = cp; 30638420Smckusick } else 30738420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 30838420Smckusick *mq = mp; 30941902Smckusick return (0); 31038420Smckusick } 31138420Smckusick 31238420Smckusick /* 31338420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 31438420Smckusick * pointed to by returned val. 31538420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 31638420Smckusick * This is used by the macros nfsm_disect and nfsm_disecton for tough 31738420Smckusick * cases. (The macros use the vars. dpos and dpos2) 31838420Smckusick */ 31938420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 32038420Smckusick struct mbuf **mdp; 32138420Smckusick caddr_t *dposp; 32238420Smckusick int siz; 32338420Smckusick int left; 32438420Smckusick int updateflg; 32538420Smckusick caddr_t *cp2; 32638420Smckusick { 32738420Smckusick register struct mbuf *mp, *mp2; 32838420Smckusick register int siz2, xfer; 32938420Smckusick register caddr_t p; 33038420Smckusick 33138420Smckusick mp = *mdp; 33238420Smckusick while (left == 0) { 33338420Smckusick *mdp = mp = mp->m_next; 33438420Smckusick if (mp == NULL) 33541902Smckusick return (EBADRPC); 33638420Smckusick left = mp->m_len; 33738420Smckusick *dposp = mtod(mp, caddr_t); 33838420Smckusick } 33938420Smckusick if (left >= siz) { 34038420Smckusick *cp2 = *dposp; 34138420Smckusick *dposp += siz; 34238420Smckusick } else if (mp->m_next == NULL) { 34341902Smckusick return (EBADRPC); 34441902Smckusick } else if (siz > MHLEN) { 34538420Smckusick panic("nfs S too big"); 34638420Smckusick } else { 34738420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 34838420Smckusick if (updateflg) { 34938420Smckusick NFSMINOFF(mp); 35038420Smckusick } else { 35138420Smckusick MGET(mp2, M_WAIT, MT_DATA); 35238420Smckusick mp2->m_next = mp->m_next; 35338420Smckusick mp->m_next = mp2; 35438420Smckusick mp->m_len -= left; 35538420Smckusick mp = mp2; 35638420Smckusick } 35738420Smckusick *cp2 = p = mtod(mp, caddr_t); 35838420Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 35938420Smckusick siz2 = siz-left; 36038420Smckusick p += left; 36138420Smckusick mp2 = mp->m_next; 36241902Smckusick /* Loop around copying up the siz2 bytes */ 36338420Smckusick while (siz2 > 0) { 36438420Smckusick if (mp2 == NULL) 36538420Smckusick return (EBADRPC); 36638420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 36741902Smckusick if (xfer > 0) { 36841902Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 36941902Smckusick NFSMADV(mp2, xfer); 37041902Smckusick mp2->m_len -= xfer; 37141902Smckusick p += xfer; 37241902Smckusick siz2 -= xfer; 37341902Smckusick } 37438420Smckusick if (siz2 > 0) 37538420Smckusick mp2 = mp2->m_next; 37638420Smckusick } 37738420Smckusick mp->m_len = siz; 37838420Smckusick *mdp = mp2; 37938420Smckusick *dposp = mtod(mp2, caddr_t); 38038420Smckusick } 38139494Smckusick return (0); 38238420Smckusick } 38338420Smckusick 38438420Smckusick /* 38541902Smckusick * Advance the position in the mbuf chain. 38638420Smckusick */ 38738420Smckusick nfs_adv(mdp, dposp, offs, left) 38838420Smckusick struct mbuf **mdp; 38938420Smckusick caddr_t *dposp; 39038420Smckusick int offs; 39138420Smckusick int left; 39238420Smckusick { 39338420Smckusick register struct mbuf *m; 39438420Smckusick register int s; 39538420Smckusick 39638420Smckusick m = *mdp; 39738420Smckusick s = left; 39838420Smckusick while (s < offs) { 39938420Smckusick offs -= s; 40038420Smckusick m = m->m_next; 40138420Smckusick if (m == NULL) 40241902Smckusick return (EBADRPC); 40338420Smckusick s = m->m_len; 40438420Smckusick } 40538420Smckusick *mdp = m; 40638420Smckusick *dposp = mtod(m, caddr_t)+offs; 40741902Smckusick return (0); 40838420Smckusick } 40938420Smckusick 41038420Smckusick /* 41138420Smckusick * Copy a string into mbufs for the hard cases... 41238420Smckusick */ 41338420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 41438420Smckusick struct mbuf **mb; 41538420Smckusick char **bpos; 41638420Smckusick char *cp; 41738420Smckusick long siz; 41838420Smckusick { 41938420Smckusick register struct mbuf *m1, *m2; 42038420Smckusick long left, xfer, len, tlen; 42138420Smckusick u_long *p; 42238420Smckusick int putsize; 42338420Smckusick 42438420Smckusick putsize = 1; 42538420Smckusick m2 = *mb; 42638420Smckusick left = NFSMSIZ(m2)-m2->m_len; 42738420Smckusick if (left > 0) { 42838420Smckusick p = ((u_long *)(*bpos)); 42938420Smckusick *p++ = txdr_unsigned(siz); 43038420Smckusick putsize = 0; 43138420Smckusick left -= NFSX_UNSIGNED; 43238420Smckusick m2->m_len += NFSX_UNSIGNED; 43338420Smckusick if (left > 0) { 43438420Smckusick bcopy(cp, (caddr_t) p, left); 43538420Smckusick siz -= left; 43638420Smckusick cp += left; 43738420Smckusick m2->m_len += left; 43838420Smckusick left = 0; 43938420Smckusick } 44038420Smckusick } 44138420Smckusick /* Loop arround adding mbufs */ 44238420Smckusick while (siz > 0) { 44338420Smckusick MGET(m1, M_WAIT, MT_DATA); 44438420Smckusick if (siz > MLEN) 44541902Smckusick MCLGET(m1, M_WAIT); 44638420Smckusick m1->m_len = NFSMSIZ(m1); 44738420Smckusick m2->m_next = m1; 44838420Smckusick m2 = m1; 44938420Smckusick p = mtod(m1, u_long *); 45038420Smckusick tlen = 0; 45138420Smckusick if (putsize) { 45238420Smckusick *p++ = txdr_unsigned(siz); 45338420Smckusick m1->m_len -= NFSX_UNSIGNED; 45438420Smckusick tlen = NFSX_UNSIGNED; 45538420Smckusick putsize = 0; 45638420Smckusick } 45738420Smckusick if (siz < m1->m_len) { 45838420Smckusick len = nfsm_rndup(siz); 45938420Smckusick xfer = siz; 46038420Smckusick if (xfer < len) 46138420Smckusick *(p+(xfer>>2)) = 0; 46238420Smckusick } else { 46338420Smckusick xfer = len = m1->m_len; 46438420Smckusick } 46538420Smckusick bcopy(cp, (caddr_t) p, xfer); 46638420Smckusick m1->m_len = len+tlen; 46738420Smckusick siz -= xfer; 46838420Smckusick cp += xfer; 46938420Smckusick } 47038420Smckusick *mb = m1; 47138420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 47241902Smckusick return (0); 47338420Smckusick } 47438420Smckusick 47538420Smckusick /* 47638420Smckusick * Called once to initialize data structures... 47738420Smckusick */ 47839444Smckusick nfs_init() 47938420Smckusick { 48038420Smckusick register int i; 48138420Smckusick 48238420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 48338420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 48438420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 48538420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 48638420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 48738420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 48838420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 48938420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 49038420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 49138420Smckusick nfs_true = txdr_unsigned(TRUE); 49238420Smckusick nfs_false = txdr_unsigned(FALSE); 49338420Smckusick /* Loop thru nfs procids */ 49438420Smckusick for (i = 0; i < NFS_NPROCS; i++) 49538420Smckusick nfs_procids[i] = txdr_unsigned(i); 49639345Smckusick /* Ensure async daemons disabled */ 49741902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 49839345Smckusick nfs_iodwant[i] = (struct proc *)0; 49938420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 50038420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 50139755Smckusick nfsrv_initcache(); /* Init the server request cache */ 50238884Smacklem rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 50341902Smckusick 50441902Smckusick /* 50541902Smckusick * Initialize reply list and start timer 50641902Smckusick */ 50741902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 50838420Smckusick nfs_timer(); 50938420Smckusick } 51038420Smckusick 51138420Smckusick /* 51238420Smckusick * Fill in the rest of the rpc_unixauth and return it 51338420Smckusick */ 51438420Smckusick static char *nfs_unixauth(cr) 51538420Smckusick register struct ucred *cr; 51638420Smckusick { 51738420Smckusick register u_long *p; 51838420Smckusick register int i; 51938420Smckusick int ngr; 52038420Smckusick 52138420Smckusick /* Maybe someday there should be a cache of AUTH_SHORT's */ 52238420Smckusick if ((p = rpc_uidp) == NULL) { 52338425Smckusick #ifdef FILLINHOST 52444987Smckusick i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED); 52538425Smckusick #else 52644987Smckusick i = 25*NFSX_UNSIGNED; 52738425Smckusick #endif 52838420Smckusick MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 52938420Smckusick bzero((caddr_t)p, i); 53038420Smckusick rpc_unixauth = (caddr_t)p; 53138420Smckusick *p++ = txdr_unsigned(RPCAUTH_UNIX); 53238420Smckusick p++; /* Fill in size later */ 53338420Smckusick *p++ = hostid; 53438425Smckusick #ifdef FILLINHOST 53538420Smckusick *p++ = txdr_unsigned(hostnamelen); 53638420Smckusick i = nfsm_rndup(hostnamelen); 53738420Smckusick bcopy(hostname, (caddr_t)p, hostnamelen); 53838420Smckusick p += (i>>2); 53938425Smckusick #else 54038425Smckusick *p++ = 0; 54138425Smckusick #endif 54238420Smckusick rpc_uidp = p; 54338420Smckusick } 54438420Smckusick *p++ = txdr_unsigned(cr->cr_uid); 54538420Smckusick *p++ = txdr_unsigned(cr->cr_groups[0]); 54644987Smckusick ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1); 54738420Smckusick *p++ = txdr_unsigned(ngr); 54844987Smckusick for (i = 1; i <= ngr; i++) 54938420Smckusick *p++ = txdr_unsigned(cr->cr_groups[i]); 55038420Smckusick /* And add the AUTH_NULL */ 55138420Smckusick *p++ = 0; 55238420Smckusick *p = 0; 55338420Smckusick i = (((caddr_t)p)-rpc_unixauth)-12; 55438420Smckusick p = (u_long *)(rpc_unixauth+4); 55538420Smckusick *p = txdr_unsigned(i); 55641902Smckusick return (rpc_unixauth); 55738420Smckusick } 55838420Smckusick 55938420Smckusick /* 56038420Smckusick * Attribute cache routines. 56138420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 56238420Smckusick * that are on the mbuf list 56338420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 56438420Smckusick * error otherwise 56538420Smckusick */ 56638420Smckusick 56738420Smckusick /* 56839444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 56938420Smckusick * the values on the mbuf list and 57038420Smckusick * Iff vap not NULL 57138420Smckusick * copy the attributes to *vaper 57238420Smckusick */ 57339457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 57439457Smckusick struct vnode **vpp; 57538420Smckusick struct mbuf **mdp; 57638420Smckusick caddr_t *dposp; 57738420Smckusick struct vattr *vaper; 57838420Smckusick { 57939457Smckusick register struct vnode *vp = *vpp; 58038420Smckusick register struct vattr *vap; 58138884Smacklem register struct nfsv2_fattr *fp; 58239444Smckusick extern struct vnodeops spec_nfsv2nodeops; 58339457Smckusick register struct nfsnode *np; 58439494Smckusick register long t1; 58539494Smckusick caddr_t dpos, cp2; 58639494Smckusick int error = 0; 58739494Smckusick struct mbuf *md; 58839444Smckusick enum vtype type; 58942244Smckusick long rdev; 59039444Smckusick struct timeval mtime; 59139444Smckusick struct vnode *nvp; 59238420Smckusick 59338420Smckusick md = *mdp; 59438420Smckusick dpos = *dposp; 59538420Smckusick t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 59638420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 59738420Smckusick return (error); 59838884Smacklem fp = (struct nfsv2_fattr *)cp2; 59939444Smckusick type = nfstov_type(fp->fa_type); 60042244Smckusick rdev = fxdr_unsigned(long, fp->fa_rdev); 60139444Smckusick fxdr_time(&fp->fa_mtime, &mtime); 60239444Smckusick /* 60339444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 60439444Smckusick * n_mtime fields. Check to see if it represents a special 60539444Smckusick * device, and if so, check for a possible alias. Once the 60639444Smckusick * correct vnode has been obtained, fill in the rest of the 60739444Smckusick * information. 60839444Smckusick */ 60938420Smckusick np = VTONFS(vp); 61039444Smckusick if (vp->v_type == VNON) { 61142244Smckusick if (type == VCHR && rdev == 0xffffffff) 61242244Smckusick vp->v_type = type = VFIFO; 61342244Smckusick else 61442244Smckusick vp->v_type = type; 61540295Smckusick if (vp->v_type == VFIFO) { 61640295Smckusick #ifdef FIFO 61740295Smckusick extern struct vnodeops fifo_nfsv2nodeops; 61840295Smckusick vp->v_op = &fifo_nfsv2nodeops; 61940295Smckusick #else 62040295Smckusick return (EOPNOTSUPP); 62140295Smckusick #endif /* FIFO */ 62240295Smckusick } 62339444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 62439444Smckusick vp->v_op = &spec_nfsv2nodeops; 62542244Smckusick if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 62639444Smckusick /* 62739444Smckusick * Reinitialize aliased node. 62839444Smckusick */ 62939444Smckusick np = VTONFS(nvp); 63039444Smckusick np->n_vnode = nvp; 63139907Smckusick np->n_flag = 0; 63239907Smckusick nfs_lock(nvp); 63339444Smckusick bcopy((caddr_t)&VTONFS(vp)->n_fh, 63439444Smckusick (caddr_t)&np->n_fh, NFSX_FH); 63539444Smckusick insque(np, nfs_hash(&np->n_fh)); 63639444Smckusick np->n_attrstamp = 0; 63739444Smckusick np->n_sillyrename = (struct sillyrename *)0; 63839444Smckusick /* 63939457Smckusick * Discard unneeded vnode and update actual one 64039444Smckusick */ 64139444Smckusick vput(vp); 64241902Smckusick *vpp = nvp; 64339444Smckusick } 64439444Smckusick } 64539444Smckusick np->n_mtime = mtime.tv_sec; 64639444Smckusick } 64738420Smckusick vap = &np->n_vattr; 64839444Smckusick vap->va_type = type; 64938884Smacklem vap->va_mode = nfstov_mode(fp->fa_mode); 65038884Smacklem vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 65138884Smacklem vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 65238884Smacklem vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 65338884Smacklem vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 65445716Smckusick if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) { 65538884Smacklem np->n_size = vap->va_size; 65645907Smckusick #ifdef NVM 65745716Smckusick vnode_pager_setsize(vp, np->n_size); 65845907Smckusick #endif 65945716Smckusick } 66040642Smckusick vap->va_size_rsv = 0; 66138884Smacklem vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 66242244Smckusick vap->va_rdev = (dev_t)rdev; 66342244Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 66440642Smckusick vap->va_bytes_rsv = 0; 66542878Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 66638884Smacklem vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 66739755Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 66839755Smckusick vap->va_atime.tv_usec = 0; 66939755Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 67039444Smckusick vap->va_mtime = mtime; 67139755Smckusick vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 67239755Smckusick vap->va_ctime.tv_usec = 0; 67339755Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 67438420Smckusick np->n_attrstamp = time.tv_sec; 67538420Smckusick *dposp = dpos; 67638420Smckusick *mdp = md; 67738884Smacklem if (vaper != NULL) { 67838420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 67938884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 68038884Smacklem vaper->va_size = np->n_size; 68138884Smacklem } 68238420Smckusick return (0); 68338420Smckusick } 68438420Smckusick 68538420Smckusick /* 68638420Smckusick * Check the time stamp 68738420Smckusick * If the cache is valid, copy contents to *vap and return 0 68838420Smckusick * otherwise return an error 68938420Smckusick */ 69038420Smckusick nfs_getattrcache(vp, vap) 69138420Smckusick register struct vnode *vp; 69238420Smckusick struct vattr *vap; 69338420Smckusick { 69438420Smckusick register struct nfsnode *np; 69538420Smckusick 69638420Smckusick np = VTONFS(vp); 69738420Smckusick if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 69838420Smckusick nfsstats.attrcache_hits++; 69938420Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 70045716Smckusick if ((np->n_flag & NMODIFIED) == 0) { 70139361Smckusick np->n_size = vap->va_size; 70245907Smckusick #ifdef NVM 70345716Smckusick vnode_pager_setsize(vp, np->n_size); 70445907Smckusick #endif 70545716Smckusick } else if (np->n_size > vap->va_size) 70638884Smacklem vap->va_size = np->n_size; 70738420Smckusick return (0); 70838420Smckusick } else { 70938420Smckusick nfsstats.attrcache_misses++; 71038420Smckusick return (ENOENT); 71138420Smckusick } 71238420Smckusick } 71338420Smckusick 71438420Smckusick /* 71541902Smckusick * Set up nameidata for a namei() call and do it 71638420Smckusick */ 71738420Smckusick nfs_namei(ndp, fhp, len, mdp, dposp) 71838420Smckusick register struct nameidata *ndp; 71938420Smckusick fhandle_t *fhp; 72038420Smckusick int len; 72138420Smckusick struct mbuf **mdp; 72238420Smckusick caddr_t *dposp; 72338420Smckusick { 72438420Smckusick register int i, rem; 72538420Smckusick register struct mbuf *md; 72638420Smckusick register char *cp; 727*45921Smckusick register struct filedesc *fdp = u.u_procp->p_fd; /* XXX */ 728*45921Smckusick struct vnode *dp, *savedcdir, *savedrdir; 72938420Smckusick int flag; 73041902Smckusick int error; 73138420Smckusick 73242244Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) { 73342244Smckusick flag = ndp->ni_nameiop & OPFLAG; 73442244Smckusick /* 73542244Smckusick * Copy the name from the mbuf list to the d_name field of ndp 73642244Smckusick * and set the various ndp fields appropriately. 73742244Smckusick */ 73842244Smckusick cp = *dposp; 73942244Smckusick md = *mdp; 74042244Smckusick rem = mtod(md, caddr_t)+md->m_len-cp; 74142244Smckusick ndp->ni_hash = 0; 74242244Smckusick for (i = 0; i < len;) { 74342244Smckusick while (rem == 0) { 74442244Smckusick md = md->m_next; 74542244Smckusick if (md == NULL) 74642244Smckusick return (EBADRPC); 74742244Smckusick cp = mtod(md, caddr_t); 74842244Smckusick rem = md->m_len; 74942244Smckusick } 75042244Smckusick if (*cp == '\0' || *cp == '/') 75142244Smckusick return (EINVAL); 75242244Smckusick if (*cp & 0200) 75342244Smckusick if ((*cp&0377) == ('/'|0200) || flag != DELETE) 75442244Smckusick return (EINVAL); 75542244Smckusick ndp->ni_dent.d_name[i++] = *cp; 75642244Smckusick ndp->ni_hash += (unsigned char)*cp * i; 75742244Smckusick cp++; 75842244Smckusick rem--; 75938420Smckusick } 76042244Smckusick *mdp = md; 76142244Smckusick *dposp = cp; 76242244Smckusick len = nfsm_rndup(len)-len; 76342244Smckusick if (len > 0) { 76442244Smckusick if (rem < len) { 76542244Smckusick if (error = nfs_adv(mdp, dposp, len, rem)) 76642244Smckusick return (error); 76742244Smckusick } else 76842244Smckusick *dposp += len; 76942244Smckusick } 77042244Smckusick } else 77142244Smckusick i = len; 77238420Smckusick ndp->ni_namelen = i; 77338420Smckusick ndp->ni_dent.d_namlen = i; 77438420Smckusick ndp->ni_dent.d_name[i] = '\0'; 77542244Smckusick ndp->ni_segflg = UIO_SYSSPACE; 77638425Smckusick ndp->ni_pathlen = 1; 77741902Smckusick ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 77838420Smckusick ndp->ni_next = &ndp->ni_dent.d_name[i]; 77941902Smckusick ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF); 78038420Smckusick 78141902Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 78238420Smckusick return (error); 78338425Smckusick if (dp->v_type != VDIR) { 78441902Smckusick vrele(dp); 78538425Smckusick return (ENOTDIR); 78638425Smckusick } 78739345Smckusick /* 78839345Smckusick * Must set current directory here to avoid confusion in namei() 78939345Smckusick * called from rename() 79039345Smckusick */ 791*45921Smckusick savedcdir = fdp->fd_cdir; 792*45921Smckusick savedrdir = fdp->fd_rdir; 793*45921Smckusick fdp->fd_cdir = dp; 794*45921Smckusick fdp->fd_rdir = NULLVP; 79538420Smckusick 79638420Smckusick /* 79741902Smckusick * And call namei() to do the real work 79838420Smckusick */ 79941902Smckusick error = namei(ndp); 800*45921Smckusick fdp->fd_cdir = savedcdir; 801*45921Smckusick fdp->fd_rdir = savedrdir; 80241902Smckusick vrele(dp); 80338420Smckusick return (error); 80438420Smckusick } 80538420Smckusick 80638420Smckusick /* 80738420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 80838420Smckusick * boundary and only trims off the back end 80938420Smckusick */ 81038420Smckusick nfsm_adj(mp, len, nul) 81138420Smckusick struct mbuf *mp; 81238420Smckusick register int len; 81338420Smckusick int nul; 81438420Smckusick { 81538420Smckusick register struct mbuf *m; 81638420Smckusick register int count, i; 81738420Smckusick register char *cp; 81838420Smckusick 81938420Smckusick /* 82038420Smckusick * Trim from tail. Scan the mbuf chain, 82138420Smckusick * calculating its length and finding the last mbuf. 82238420Smckusick * If the adjustment only affects this mbuf, then just 82338420Smckusick * adjust and return. Otherwise, rescan and truncate 82438420Smckusick * after the remaining size. 82538420Smckusick */ 82638420Smckusick count = 0; 82738420Smckusick m = mp; 82838420Smckusick for (;;) { 82938420Smckusick count += m->m_len; 83038420Smckusick if (m->m_next == (struct mbuf *)0) 83138420Smckusick break; 83238420Smckusick m = m->m_next; 83338420Smckusick } 83438579Smckusick if (m->m_len > len) { 83538420Smckusick m->m_len -= len; 83638420Smckusick if (nul > 0) { 83738420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 83838420Smckusick for (i = 0; i < nul; i++) 83938420Smckusick *cp++ = '\0'; 84038420Smckusick } 84138420Smckusick return; 84238420Smckusick } 84338420Smckusick count -= len; 84438420Smckusick if (count < 0) 84538420Smckusick count = 0; 84638420Smckusick /* 84738420Smckusick * Correct length for chain is "count". 84838420Smckusick * Find the mbuf with last data, adjust its length, 84938420Smckusick * and toss data from remaining mbufs on chain. 85038420Smckusick */ 85138420Smckusick for (m = mp; m; m = m->m_next) { 85238420Smckusick if (m->m_len >= count) { 85338420Smckusick m->m_len = count; 85438420Smckusick if (nul > 0) { 85538420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 85638420Smckusick for (i = 0; i < nul; i++) 85738420Smckusick *cp++ = '\0'; 85838420Smckusick } 85938420Smckusick break; 86038420Smckusick } 86138420Smckusick count -= m->m_len; 86238420Smckusick } 86338420Smckusick while (m = m->m_next) 86438420Smckusick m->m_len = 0; 86538420Smckusick } 86638420Smckusick 86738420Smckusick /* 86838420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 86938420Smckusick * - look up fsid in mount list (if not found ret error) 87038420Smckusick * - check that it is exported 87138420Smckusick * - get vp by calling VFS_FHTOVP() macro 87238420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 87341902Smckusick * - if cred->cr_uid == 0 set it to m_exroot 87438420Smckusick */ 87538420Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred) 87638420Smckusick fhandle_t *fhp; 87738420Smckusick int lockflag; 87838420Smckusick struct vnode **vpp; 87938420Smckusick struct ucred *cred; 88038420Smckusick { 88138420Smckusick register struct mount *mp; 88238420Smckusick 88338420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 88438420Smckusick return (ESTALE); 88541398Smckusick if ((mp->mnt_flag & MNT_EXPORTED) == 0) 88638420Smckusick return (EACCES); 88738420Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 88838420Smckusick return (ESTALE); 88938420Smckusick if (cred->cr_uid == 0) 89041398Smckusick cred->cr_uid = mp->mnt_exroot; 89138420Smckusick if (!lockflag) 89238420Smckusick VOP_UNLOCK(*vpp); 89338420Smckusick return (0); 89438420Smckusick } 89545282Smckusick 89645282Smckusick /* 89745282Smckusick * These two functions implement nfs rpc compression. 89845282Smckusick * The algorithm is a trivial run length encoding of '\0' bytes. The high 89945282Smckusick * order nibble of hex "e" is or'd with the number of zeroes - 2 in four 90045282Smckusick * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e" 90145282Smckusick * is byte stuffed. 90245282Smckusick * The compressed data is padded with 0x0 bytes to an even multiple of 90345282Smckusick * 4 bytes in length to avoid any weird long pointer alignments. 90445282Smckusick * If compression/uncompression is unsuccessful, the original mbuf list 90545282Smckusick * is returned. 90645282Smckusick * The first four bytes (the XID) are left uncompressed and the fifth 90745282Smckusick * byte is set to 0x1 for request and 0x2 for reply. 90845282Smckusick * An uncompressed RPC will always have the fifth byte == 0x0. 90945282Smckusick */ 91045282Smckusick struct mbuf * 91145282Smckusick nfs_compress(m0) 91245282Smckusick struct mbuf *m0; 91345282Smckusick { 91445282Smckusick register u_char ch, nextch; 91545282Smckusick register int i, rlelast; 91645282Smckusick register u_char *ip, *op; 91745282Smckusick register int ileft, oleft, noteof; 91845282Smckusick register struct mbuf *m, *om; 91945282Smckusick struct mbuf **mp, *retm; 92045282Smckusick int olen, clget; 92145282Smckusick 92245282Smckusick i = rlelast = 0; 92345282Smckusick noteof = 1; 92445282Smckusick m = m0; 92545282Smckusick if (m->m_len < 12) 92645282Smckusick return (m0); 92745282Smckusick if (m->m_pkthdr.len >= MINCLSIZE) 92845282Smckusick clget = 1; 92945282Smckusick else 93045282Smckusick clget = 0; 93145282Smckusick ileft = m->m_len - 9; 93245282Smckusick ip = mtod(m, u_char *); 93345288Smckusick MGETHDR(om, M_WAIT, MT_DATA); 93445282Smckusick if (clget) 93545282Smckusick MCLGET(om, M_WAIT); 93645282Smckusick retm = om; 93745282Smckusick mp = &om->m_next; 93845282Smckusick olen = om->m_len = 5; 93945282Smckusick oleft = M_TRAILINGSPACE(om); 94045282Smckusick op = mtod(om, u_char *); 94145298Smckusick *((u_long *)op) = *((u_long *)ip); 94245282Smckusick ip += 7; 94345282Smckusick op += 4; 94445282Smckusick *op++ = *ip++ + 1; 94545282Smckusick nextch = *ip++; 94645282Smckusick while (noteof) { 94745282Smckusick ch = nextch; 94845282Smckusick if (ileft == 0) { 94945282Smckusick do { 95045282Smckusick m = m->m_next; 95145282Smckusick } while (m && m->m_len == 0); 95245282Smckusick if (m) { 95345282Smckusick ileft = m->m_len; 95445282Smckusick ip = mtod(m, u_char *); 95545282Smckusick } else { 95645282Smckusick noteof = 0; 95745282Smckusick nextch = 0x1; 95845282Smckusick goto doit; 95945282Smckusick } 96045282Smckusick } 96145282Smckusick nextch = *ip++; 96245282Smckusick ileft--; 96345282Smckusick doit: 96445282Smckusick if (ch == '\0') { 96545282Smckusick if (++i == NFSC_MAX || nextch != '\0') { 96645282Smckusick if (i < 2) { 96745282Smckusick nfscput('\0'); 96845282Smckusick } else { 96945282Smckusick if (rlelast == i) { 97045282Smckusick nfscput('\0'); 97145282Smckusick i--; 97245282Smckusick } 97345282Smckusick if (NFSCRLE(i) == (nextch & 0xff)) { 97445282Smckusick i--; 97545282Smckusick if (i < 2) { 97645282Smckusick nfscput('\0'); 97745282Smckusick } else { 97845282Smckusick nfscput(NFSCRLE(i)); 97945282Smckusick } 98045282Smckusick nfscput('\0'); 98145282Smckusick rlelast = 0; 98245282Smckusick } else { 98345282Smckusick nfscput(NFSCRLE(i)); 98445282Smckusick rlelast = i; 98545282Smckusick } 98645282Smckusick } 98745282Smckusick i = 0; 98845282Smckusick } 98945282Smckusick } else { 99045282Smckusick if ((ch & NFSCRL) == NFSCRL) { 99145282Smckusick nfscput(ch); 99245282Smckusick } 99345282Smckusick nfscput(ch); 99445282Smckusick i = rlelast = 0; 99545282Smckusick } 99645282Smckusick } 99745282Smckusick if (olen < m0->m_pkthdr.len) { 99845282Smckusick m_freem(m0); 99945282Smckusick if (i = (olen & 0x3)) { 100045282Smckusick i = 4 - i; 100145298Smckusick while (i-- > 0) { 100245282Smckusick nfscput('\0'); 100345298Smckusick } 100445282Smckusick } 100545282Smckusick retm->m_pkthdr.len = olen; 100645298Smckusick retm->m_pkthdr.rcvif = (struct ifnet *)0; 100745282Smckusick return (retm); 100845282Smckusick } else { 100945282Smckusick m_freem(retm); 101045282Smckusick return (m0); 101145282Smckusick } 101245282Smckusick } 101345282Smckusick 101445282Smckusick struct mbuf * 101545282Smckusick nfs_uncompress(m0) 101645282Smckusick struct mbuf *m0; 101745282Smckusick { 101845282Smckusick register u_char cp, nextcp, *ip, *op; 101945282Smckusick register struct mbuf *m, *om; 102045282Smckusick struct mbuf *retm, **mp; 102145282Smckusick int i, j, noteof, clget, ileft, oleft, olen; 102245282Smckusick 102345282Smckusick m = m0; 102445298Smckusick i = 0; 102545298Smckusick while (m && i < MINCLSIZE) { 102645298Smckusick i += m->m_len; 102745298Smckusick m = m->m_next; 102845298Smckusick } 102945298Smckusick if (i < 6) 103045282Smckusick return (m0); 103145298Smckusick if (i >= MINCLSIZE) 103245282Smckusick clget = 1; 103345282Smckusick else 103445282Smckusick clget = 0; 103545298Smckusick m = m0; 103645298Smckusick MGET(om, M_WAIT, MT_DATA); 103745282Smckusick if (clget) 103845282Smckusick MCLGET(om, M_WAIT); 103945282Smckusick olen = om->m_len = 8; 104045282Smckusick oleft = M_TRAILINGSPACE(om); 104145282Smckusick op = mtod(om, u_char *); 104245282Smckusick retm = om; 104345282Smckusick mp = &om->m_next; 104445282Smckusick if (m->m_len >= 6) { 104545282Smckusick ileft = m->m_len - 6; 104645282Smckusick ip = mtod(m, u_char *); 104745282Smckusick *((u_long *)op) = *((u_long *)ip); 104845282Smckusick bzero(op + 4, 3); 104945282Smckusick ip += 4; 105045282Smckusick op += 7; 105145282Smckusick if (*ip == '\0') { 105245282Smckusick m_freem(om); 105345282Smckusick return (m0); 105445282Smckusick } 105545282Smckusick *op++ = *ip++ - 1; 105645282Smckusick cp = *ip++; 105745282Smckusick } else { 105845282Smckusick ileft = m->m_len; 105945282Smckusick ip = mtod(m, u_char *); 106045282Smckusick nfscget(*op++); 106145282Smckusick nfscget(*op++); 106245282Smckusick nfscget(*op++); 106345282Smckusick nfscget(*op++); 106445282Smckusick bzero(op, 3); 106545282Smckusick op += 3; 106645282Smckusick nfscget(*op); 106745282Smckusick if (*op == '\0') { 106845282Smckusick m_freem(om); 106945282Smckusick return (m0); 107045282Smckusick } 107145282Smckusick (*op)--; 107245282Smckusick op++; 107345282Smckusick nfscget(cp); 107445282Smckusick } 107545282Smckusick noteof = 1; 107645282Smckusick while (noteof) { 107745282Smckusick if ((cp & NFSCRL) == NFSCRL) { 107845282Smckusick nfscget(nextcp); 107945282Smckusick if (cp == nextcp) { 108045282Smckusick nfscput(cp); 108145282Smckusick goto readit; 108245282Smckusick } else { 108345282Smckusick i = (cp & 0xf) + 2; 108445282Smckusick for (j = 0; j < i; j++) { 108545282Smckusick nfscput('\0'); 108645282Smckusick } 108745282Smckusick cp = nextcp; 108845282Smckusick } 108945282Smckusick } else { 109045282Smckusick nfscput(cp); 109145282Smckusick readit: 109245282Smckusick nfscget(cp); 109345282Smckusick } 109445282Smckusick } 109545282Smckusick m_freem(m0); 109645298Smckusick if (i = (olen & 0x3)) 109745282Smckusick om->m_len -= i; 109845282Smckusick return (retm); 109945282Smckusick } 1100