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*44987Smckusick * @(#)nfs_subs.c 7.29 (Berkeley) 07/26/90 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" 2140136Smckusick #include "systm.h" 2240136Smckusick #include "kernel.h" 2338420Smckusick #include "mount.h" 2438420Smckusick #include "file.h" 2538420Smckusick #include "vnode.h" 2640136Smckusick #include "mbuf.h" 2740136Smckusick #include "errno.h" 2838884Smacklem #include "map.h" 2938420Smckusick #include "rpcv2.h" 3038420Smckusick #include "nfsv2.h" 3138420Smckusick #include "nfsnode.h" 3238420Smckusick #include "nfs.h" 3338884Smacklem #include "nfsiom.h" 3438420Smckusick #include "xdr_subs.h" 3538420Smckusick #include "nfsm_subs.h" 3638420Smckusick 3738420Smckusick #define TRUE 1 3838420Smckusick #define FALSE 0 3938420Smckusick 4038420Smckusick /* 4138420Smckusick * Data items converted to xdr at startup, since they are constant 4238420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 4338420Smckusick */ 4438420Smckusick u_long nfs_procids[NFS_NPROCS]; 4538420Smckusick u_long nfs_xdrneg1; 4638420Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 4738420Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 4838420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 4938420Smckusick /* And other global data */ 5038420Smckusick static u_long *rpc_uidp = (u_long *)0; 5138420Smckusick static u_long nfs_xid = 1; 5238420Smckusick static char *rpc_unixauth; 5338420Smckusick extern long hostid; 5442244Smckusick enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 5541902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 5638884Smacklem extern struct map nfsmap[NFS_MSIZ]; 5741902Smckusick extern struct nfsreq nfsreqh; 5838420Smckusick 5938420Smckusick /* Function ret types */ 6038420Smckusick static char *nfs_unixauth(); 6138420Smckusick 6238420Smckusick /* 6338737Smckusick * Maximum number of groups passed through to NFS server. 6441902Smckusick * According to RFC1057 it should be 16. 6538737Smckusick * For release 3.X systems, the maximum value is 8. 66*44987Smckusick * For some other servers, the maximum value is 10. 6738737Smckusick */ 6838737Smckusick int numgrps = 8; 6938737Smckusick 7038737Smckusick /* 7138420Smckusick * Create the header for an rpc request packet 7238420Smckusick * The function nfs_unixauth() creates a unix style authorization string 7338420Smckusick * and returns a ptr to it. 7438420Smckusick * The hsiz is the size of the rest of the nfs request header. 7538420Smckusick * (just used to decide if a cluster is a good idea) 7639494Smckusick * nb: Note that the prog, vers and procid args are already in xdr byte order 7738420Smckusick */ 7839494Smckusick struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 7938420Smckusick u_long prog; 8038420Smckusick u_long vers; 8139494Smckusick u_long procid; 8238420Smckusick struct ucred *cred; 8338420Smckusick int hsiz; 8438420Smckusick caddr_t *bpos; 8538420Smckusick struct mbuf **mb; 8638420Smckusick u_long *retxid; 8738420Smckusick { 8838420Smckusick register struct mbuf *mreq, *m; 8938420Smckusick register u_long *p; 9038420Smckusick struct mbuf *m1; 9138420Smckusick char *ap; 9238420Smckusick int asiz, siz; 9338420Smckusick 9438420Smckusick NFSMGETHDR(mreq); 95*44987Smckusick asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps : 96*44987Smckusick (cred->cr_ngroups - 1)) << 2); 9738425Smckusick #ifdef FILLINHOST 9838420Smckusick asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 9938425Smckusick #else 10038425Smckusick asiz += 9*NFSX_UNSIGNED; 10138425Smckusick #endif 10238420Smckusick 10338420Smckusick /* If we need a lot, alloc a cluster ?? */ 10438420Smckusick if ((asiz+hsiz+RPC_SIZ) > MHLEN) 10541902Smckusick MCLGET(mreq, M_WAIT); 10638420Smckusick mreq->m_len = NFSMSIZ(mreq); 10738420Smckusick siz = mreq->m_len; 10838420Smckusick m1 = mreq; 10938420Smckusick /* 11038420Smckusick * Alloc enough mbufs 11138420Smckusick * We do it now to avoid all sleeps after the call to nfs_unixauth() 11238420Smckusick */ 11338420Smckusick while ((asiz+RPC_SIZ) > siz) { 11438420Smckusick MGET(m, M_WAIT, MT_DATA); 11538420Smckusick m1->m_next = m; 11638420Smckusick m->m_len = MLEN; 11738420Smckusick siz += MLEN; 11838420Smckusick m1 = m; 11938420Smckusick } 12038420Smckusick p = mtod(mreq, u_long *); 12138420Smckusick *p++ = *retxid = txdr_unsigned(++nfs_xid); 12238420Smckusick *p++ = rpc_call; 12338420Smckusick *p++ = rpc_vers; 12438420Smckusick *p++ = prog; 12538420Smckusick *p++ = vers; 12639494Smckusick *p++ = procid; 12738420Smckusick 12838420Smckusick /* Now we can call nfs_unixauth() and copy it in */ 12938420Smckusick ap = nfs_unixauth(cred); 13038420Smckusick m = mreq; 13138420Smckusick siz = m->m_len-RPC_SIZ; 13238420Smckusick if (asiz <= siz) { 13338420Smckusick bcopy(ap, (caddr_t)p, asiz); 13438420Smckusick m->m_len = asiz+RPC_SIZ; 13538420Smckusick } else { 13638420Smckusick bcopy(ap, (caddr_t)p, siz); 13738420Smckusick ap += siz; 13838420Smckusick asiz -= siz; 13938420Smckusick while (asiz > 0) { 14038420Smckusick siz = (asiz > MLEN) ? MLEN : asiz; 14138420Smckusick m = m->m_next; 14238420Smckusick bcopy(ap, mtod(m, caddr_t), siz); 14338420Smckusick m->m_len = siz; 14438420Smckusick asiz -= siz; 14538420Smckusick ap += siz; 14638420Smckusick } 14738420Smckusick } 14838420Smckusick 14938420Smckusick /* Finally, return values */ 15038420Smckusick *mb = m; 15138420Smckusick *bpos = mtod(m, caddr_t)+m->m_len; 15238420Smckusick return (mreq); 15338420Smckusick } 15438420Smckusick 15538420Smckusick /* 15638420Smckusick * copies mbuf chain to the uio scatter/gather list 15738420Smckusick */ 15838420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 15938420Smckusick struct mbuf **mrep; 16043353Smckusick register struct uio *uiop; 16138420Smckusick int siz; 16238420Smckusick caddr_t *dpos; 16338420Smckusick { 16443353Smckusick register char *mbufcp, *uiocp; 16538420Smckusick register int xfer, left, len; 16638420Smckusick register struct mbuf *mp; 16738420Smckusick long uiosiz, rem; 16841902Smckusick int error = 0; 16938420Smckusick 17038420Smckusick mp = *mrep; 17138420Smckusick mbufcp = *dpos; 17238420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 17338420Smckusick rem = nfsm_rndup(siz)-siz; 17438420Smckusick while (siz > 0) { 17538420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 17641902Smckusick return (EFBIG); 17738420Smckusick left = uiop->uio_iov->iov_len; 17838420Smckusick uiocp = uiop->uio_iov->iov_base; 17938420Smckusick if (left > siz) 18038420Smckusick left = siz; 18138420Smckusick uiosiz = left; 18238420Smckusick while (left > 0) { 18338420Smckusick while (len == 0) { 18438420Smckusick mp = mp->m_next; 18538420Smckusick if (mp == NULL) 18638420Smckusick return (EBADRPC); 18738420Smckusick mbufcp = mtod(mp, caddr_t); 18838420Smckusick len = mp->m_len; 18938420Smckusick } 19038420Smckusick xfer = (left > len) ? len : left; 19138420Smckusick #ifdef notdef 19238420Smckusick /* Not Yet.. */ 19338420Smckusick if (uiop->uio_iov->iov_op != NULL) 19438420Smckusick (*(uiop->uio_iov->iov_op)) 19538420Smckusick (mbufcp, uiocp, xfer); 19638420Smckusick else 19738420Smckusick #endif 19838420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 19938420Smckusick bcopy(mbufcp, uiocp, xfer); 20038420Smckusick else 20138420Smckusick copyout(mbufcp, uiocp, xfer); 20238420Smckusick left -= xfer; 20338420Smckusick len -= xfer; 20438420Smckusick mbufcp += xfer; 20538420Smckusick uiocp += xfer; 20639585Smckusick uiop->uio_offset += xfer; 20738420Smckusick uiop->uio_resid -= xfer; 20838420Smckusick } 20938420Smckusick if (uiop->uio_iov->iov_len <= siz) { 21038420Smckusick uiop->uio_iovcnt--; 21138420Smckusick uiop->uio_iov++; 21238420Smckusick } else { 21338420Smckusick uiop->uio_iov->iov_base += uiosiz; 21438420Smckusick uiop->uio_iov->iov_len -= uiosiz; 21538420Smckusick } 21638420Smckusick siz -= uiosiz; 21738420Smckusick } 21838420Smckusick *dpos = mbufcp; 21938420Smckusick *mrep = mp; 22041902Smckusick if (rem > 0) { 22141902Smckusick if (len < rem) 22241902Smckusick error = nfs_adv(mrep, dpos, rem, len); 22341902Smckusick else 22441902Smckusick *dpos += rem; 22541902Smckusick } 22641902Smckusick return (error); 22738420Smckusick } 22838420Smckusick 22938420Smckusick /* 23038420Smckusick * copies a uio scatter/gather list to an mbuf chain... 23138420Smckusick */ 23238420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 23338420Smckusick register struct uio *uiop; 23438420Smckusick struct mbuf **mq; 23538420Smckusick int siz; 23638420Smckusick caddr_t *bpos; 23738420Smckusick { 23843353Smckusick register char *uiocp; 23943353Smckusick register struct mbuf *mp, *mp2; 24043353Smckusick register int xfer, left, len; 24143353Smckusick int uiosiz, clflg, rem; 24243353Smckusick char *cp; 24338420Smckusick 24438420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 24538420Smckusick clflg = 1; 24638420Smckusick else 24738420Smckusick clflg = 0; 24838420Smckusick rem = nfsm_rndup(siz)-siz; 24938420Smckusick mp2 = *mq; 25038420Smckusick while (siz > 0) { 25138420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 25241902Smckusick return (EINVAL); 25338420Smckusick left = uiop->uio_iov->iov_len; 25438420Smckusick uiocp = uiop->uio_iov->iov_base; 25538420Smckusick if (left > siz) 25638420Smckusick left = siz; 25738420Smckusick uiosiz = left; 25838420Smckusick while (left > 0) { 25938420Smckusick MGET(mp, M_WAIT, MT_DATA); 26038420Smckusick if (clflg) 26141902Smckusick MCLGET(mp, M_WAIT); 26238420Smckusick mp->m_len = NFSMSIZ(mp); 26338420Smckusick mp2->m_next = mp; 26438420Smckusick mp2 = mp; 26538420Smckusick xfer = (left > mp->m_len) ? mp->m_len : left; 26638420Smckusick #ifdef notdef 26738420Smckusick /* Not Yet.. */ 26838420Smckusick if (uiop->uio_iov->iov_op != NULL) 26938420Smckusick (*(uiop->uio_iov->iov_op)) 27038420Smckusick (uiocp, mtod(mp, caddr_t), xfer); 27138420Smckusick else 27238420Smckusick #endif 27338420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 27438420Smckusick bcopy(uiocp, mtod(mp, caddr_t), xfer); 27538420Smckusick else 27638420Smckusick copyin(uiocp, mtod(mp, caddr_t), xfer); 27738420Smckusick len = mp->m_len; 27838420Smckusick mp->m_len = xfer; 27938420Smckusick left -= xfer; 28038420Smckusick uiocp += xfer; 28139585Smckusick uiop->uio_offset += xfer; 28238420Smckusick uiop->uio_resid -= xfer; 28338420Smckusick } 28438420Smckusick if (uiop->uio_iov->iov_len <= siz) { 28538420Smckusick uiop->uio_iovcnt--; 28638420Smckusick uiop->uio_iov++; 28738420Smckusick } else { 28838420Smckusick uiop->uio_iov->iov_base += uiosiz; 28938420Smckusick uiop->uio_iov->iov_len -= uiosiz; 29038420Smckusick } 29138420Smckusick siz -= uiosiz; 29238420Smckusick } 29338420Smckusick if (rem > 0) { 29438420Smckusick if (rem > (len-mp->m_len)) { 29538420Smckusick MGET(mp, M_WAIT, MT_DATA); 29638420Smckusick mp->m_len = 0; 29738420Smckusick mp2->m_next = mp; 29838420Smckusick } 29938420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 30038420Smckusick for (left = 0; left < rem; left++) 30138420Smckusick *cp++ = '\0'; 30238420Smckusick mp->m_len += rem; 30338420Smckusick *bpos = cp; 30438420Smckusick } else 30538420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 30638420Smckusick *mq = mp; 30741902Smckusick return (0); 30838420Smckusick } 30938420Smckusick 31038420Smckusick /* 31138420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 31238420Smckusick * pointed to by returned val. 31338420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 31438420Smckusick * This is used by the macros nfsm_disect and nfsm_disecton for tough 31538420Smckusick * cases. (The macros use the vars. dpos and dpos2) 31638420Smckusick */ 31738420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 31838420Smckusick struct mbuf **mdp; 31938420Smckusick caddr_t *dposp; 32038420Smckusick int siz; 32138420Smckusick int left; 32238420Smckusick int updateflg; 32338420Smckusick caddr_t *cp2; 32438420Smckusick { 32538420Smckusick register struct mbuf *mp, *mp2; 32638420Smckusick register int siz2, xfer; 32738420Smckusick register caddr_t p; 32838420Smckusick 32938420Smckusick mp = *mdp; 33038420Smckusick while (left == 0) { 33138420Smckusick *mdp = mp = mp->m_next; 33238420Smckusick if (mp == NULL) 33341902Smckusick return (EBADRPC); 33438420Smckusick left = mp->m_len; 33538420Smckusick *dposp = mtod(mp, caddr_t); 33638420Smckusick } 33738420Smckusick if (left >= siz) { 33838420Smckusick *cp2 = *dposp; 33938420Smckusick *dposp += siz; 34038420Smckusick } else if (mp->m_next == NULL) { 34141902Smckusick return (EBADRPC); 34241902Smckusick } else if (siz > MHLEN) { 34338420Smckusick panic("nfs S too big"); 34438420Smckusick } else { 34538420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 34638420Smckusick if (updateflg) { 34738420Smckusick NFSMINOFF(mp); 34838420Smckusick } else { 34938420Smckusick MGET(mp2, M_WAIT, MT_DATA); 35038420Smckusick mp2->m_next = mp->m_next; 35138420Smckusick mp->m_next = mp2; 35238420Smckusick mp->m_len -= left; 35338420Smckusick mp = mp2; 35438420Smckusick } 35538420Smckusick *cp2 = p = mtod(mp, caddr_t); 35638420Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 35738420Smckusick siz2 = siz-left; 35838420Smckusick p += left; 35938420Smckusick mp2 = mp->m_next; 36041902Smckusick /* Loop around copying up the siz2 bytes */ 36138420Smckusick while (siz2 > 0) { 36238420Smckusick if (mp2 == NULL) 36338420Smckusick return (EBADRPC); 36438420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 36541902Smckusick if (xfer > 0) { 36641902Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 36741902Smckusick NFSMADV(mp2, xfer); 36841902Smckusick mp2->m_len -= xfer; 36941902Smckusick p += xfer; 37041902Smckusick siz2 -= xfer; 37141902Smckusick } 37238420Smckusick if (siz2 > 0) 37338420Smckusick mp2 = mp2->m_next; 37438420Smckusick } 37538420Smckusick mp->m_len = siz; 37638420Smckusick *mdp = mp2; 37738420Smckusick *dposp = mtod(mp2, caddr_t); 37838420Smckusick } 37939494Smckusick return (0); 38038420Smckusick } 38138420Smckusick 38238420Smckusick /* 38341902Smckusick * Advance the position in the mbuf chain. 38438420Smckusick */ 38538420Smckusick nfs_adv(mdp, dposp, offs, left) 38638420Smckusick struct mbuf **mdp; 38738420Smckusick caddr_t *dposp; 38838420Smckusick int offs; 38938420Smckusick int left; 39038420Smckusick { 39138420Smckusick register struct mbuf *m; 39238420Smckusick register int s; 39338420Smckusick 39438420Smckusick m = *mdp; 39538420Smckusick s = left; 39638420Smckusick while (s < offs) { 39738420Smckusick offs -= s; 39838420Smckusick m = m->m_next; 39938420Smckusick if (m == NULL) 40041902Smckusick return (EBADRPC); 40138420Smckusick s = m->m_len; 40238420Smckusick } 40338420Smckusick *mdp = m; 40438420Smckusick *dposp = mtod(m, caddr_t)+offs; 40541902Smckusick return (0); 40638420Smckusick } 40738420Smckusick 40838420Smckusick /* 40938420Smckusick * Copy a string into mbufs for the hard cases... 41038420Smckusick */ 41138420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 41238420Smckusick struct mbuf **mb; 41338420Smckusick char **bpos; 41438420Smckusick char *cp; 41538420Smckusick long siz; 41638420Smckusick { 41738420Smckusick register struct mbuf *m1, *m2; 41838420Smckusick long left, xfer, len, tlen; 41938420Smckusick u_long *p; 42038420Smckusick int putsize; 42138420Smckusick 42238420Smckusick putsize = 1; 42338420Smckusick m2 = *mb; 42438420Smckusick left = NFSMSIZ(m2)-m2->m_len; 42538420Smckusick if (left > 0) { 42638420Smckusick p = ((u_long *)(*bpos)); 42738420Smckusick *p++ = txdr_unsigned(siz); 42838420Smckusick putsize = 0; 42938420Smckusick left -= NFSX_UNSIGNED; 43038420Smckusick m2->m_len += NFSX_UNSIGNED; 43138420Smckusick if (left > 0) { 43238420Smckusick bcopy(cp, (caddr_t) p, left); 43338420Smckusick siz -= left; 43438420Smckusick cp += left; 43538420Smckusick m2->m_len += left; 43638420Smckusick left = 0; 43738420Smckusick } 43838420Smckusick } 43938420Smckusick /* Loop arround adding mbufs */ 44038420Smckusick while (siz > 0) { 44138420Smckusick MGET(m1, M_WAIT, MT_DATA); 44238420Smckusick if (siz > MLEN) 44341902Smckusick MCLGET(m1, M_WAIT); 44438420Smckusick m1->m_len = NFSMSIZ(m1); 44538420Smckusick m2->m_next = m1; 44638420Smckusick m2 = m1; 44738420Smckusick p = mtod(m1, u_long *); 44838420Smckusick tlen = 0; 44938420Smckusick if (putsize) { 45038420Smckusick *p++ = txdr_unsigned(siz); 45138420Smckusick m1->m_len -= NFSX_UNSIGNED; 45238420Smckusick tlen = NFSX_UNSIGNED; 45338420Smckusick putsize = 0; 45438420Smckusick } 45538420Smckusick if (siz < m1->m_len) { 45638420Smckusick len = nfsm_rndup(siz); 45738420Smckusick xfer = siz; 45838420Smckusick if (xfer < len) 45938420Smckusick *(p+(xfer>>2)) = 0; 46038420Smckusick } else { 46138420Smckusick xfer = len = m1->m_len; 46238420Smckusick } 46338420Smckusick bcopy(cp, (caddr_t) p, xfer); 46438420Smckusick m1->m_len = len+tlen; 46538420Smckusick siz -= xfer; 46638420Smckusick cp += xfer; 46738420Smckusick } 46838420Smckusick *mb = m1; 46938420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 47041902Smckusick return (0); 47138420Smckusick } 47238420Smckusick 47338420Smckusick /* 47438420Smckusick * Called once to initialize data structures... 47538420Smckusick */ 47639444Smckusick nfs_init() 47738420Smckusick { 47838420Smckusick register int i; 47938420Smckusick 48038420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 48138420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 48238420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 48338420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 48438420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 48538420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 48638420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 48738420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 48838420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 48938420Smckusick nfs_true = txdr_unsigned(TRUE); 49038420Smckusick nfs_false = txdr_unsigned(FALSE); 49138420Smckusick /* Loop thru nfs procids */ 49238420Smckusick for (i = 0; i < NFS_NPROCS; i++) 49338420Smckusick nfs_procids[i] = txdr_unsigned(i); 49439345Smckusick /* Ensure async daemons disabled */ 49541902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 49639345Smckusick nfs_iodwant[i] = (struct proc *)0; 49738420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 49838420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 49939755Smckusick nfsrv_initcache(); /* Init the server request cache */ 50038884Smacklem rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 50141902Smckusick 50241902Smckusick /* 50341902Smckusick * Initialize reply list and start timer 50441902Smckusick */ 50541902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 50638420Smckusick nfs_timer(); 50738420Smckusick } 50838420Smckusick 50938420Smckusick /* 51038420Smckusick * Fill in the rest of the rpc_unixauth and return it 51138420Smckusick */ 51238420Smckusick static char *nfs_unixauth(cr) 51338420Smckusick register struct ucred *cr; 51438420Smckusick { 51538420Smckusick register u_long *p; 51638420Smckusick register int i; 51738420Smckusick int ngr; 51838420Smckusick 51938420Smckusick /* Maybe someday there should be a cache of AUTH_SHORT's */ 52038420Smckusick if ((p = rpc_uidp) == NULL) { 52138425Smckusick #ifdef FILLINHOST 522*44987Smckusick i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED); 52338425Smckusick #else 524*44987Smckusick i = 25*NFSX_UNSIGNED; 52538425Smckusick #endif 52638420Smckusick MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 52738420Smckusick bzero((caddr_t)p, i); 52838420Smckusick rpc_unixauth = (caddr_t)p; 52938420Smckusick *p++ = txdr_unsigned(RPCAUTH_UNIX); 53038420Smckusick p++; /* Fill in size later */ 53138420Smckusick *p++ = hostid; 53238425Smckusick #ifdef FILLINHOST 53338420Smckusick *p++ = txdr_unsigned(hostnamelen); 53438420Smckusick i = nfsm_rndup(hostnamelen); 53538420Smckusick bcopy(hostname, (caddr_t)p, hostnamelen); 53638420Smckusick p += (i>>2); 53738425Smckusick #else 53838425Smckusick *p++ = 0; 53938425Smckusick #endif 54038420Smckusick rpc_uidp = p; 54138420Smckusick } 54238420Smckusick *p++ = txdr_unsigned(cr->cr_uid); 54338420Smckusick *p++ = txdr_unsigned(cr->cr_groups[0]); 544*44987Smckusick ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1); 54538420Smckusick *p++ = txdr_unsigned(ngr); 546*44987Smckusick for (i = 1; i <= ngr; i++) 54738420Smckusick *p++ = txdr_unsigned(cr->cr_groups[i]); 54838420Smckusick /* And add the AUTH_NULL */ 54938420Smckusick *p++ = 0; 55038420Smckusick *p = 0; 55138420Smckusick i = (((caddr_t)p)-rpc_unixauth)-12; 55238420Smckusick p = (u_long *)(rpc_unixauth+4); 55338420Smckusick *p = txdr_unsigned(i); 55441902Smckusick return (rpc_unixauth); 55538420Smckusick } 55638420Smckusick 55738420Smckusick /* 55838420Smckusick * Attribute cache routines. 55938420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 56038420Smckusick * that are on the mbuf list 56138420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 56238420Smckusick * error otherwise 56338420Smckusick */ 56438420Smckusick 56538420Smckusick /* 56639444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 56738420Smckusick * the values on the mbuf list and 56838420Smckusick * Iff vap not NULL 56938420Smckusick * copy the attributes to *vaper 57038420Smckusick */ 57139457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 57239457Smckusick struct vnode **vpp; 57338420Smckusick struct mbuf **mdp; 57438420Smckusick caddr_t *dposp; 57538420Smckusick struct vattr *vaper; 57638420Smckusick { 57739457Smckusick register struct vnode *vp = *vpp; 57838420Smckusick register struct vattr *vap; 57938884Smacklem register struct nfsv2_fattr *fp; 58039444Smckusick extern struct vnodeops spec_nfsv2nodeops; 58139457Smckusick register struct nfsnode *np; 58239494Smckusick register long t1; 58339494Smckusick caddr_t dpos, cp2; 58439494Smckusick int error = 0; 58539494Smckusick struct mbuf *md; 58639444Smckusick enum vtype type; 58742244Smckusick long rdev; 58839444Smckusick struct timeval mtime; 58939444Smckusick struct vnode *nvp; 59038420Smckusick 59138420Smckusick md = *mdp; 59238420Smckusick dpos = *dposp; 59338420Smckusick t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 59438420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 59538420Smckusick return (error); 59638884Smacklem fp = (struct nfsv2_fattr *)cp2; 59739444Smckusick type = nfstov_type(fp->fa_type); 59842244Smckusick rdev = fxdr_unsigned(long, fp->fa_rdev); 59939444Smckusick fxdr_time(&fp->fa_mtime, &mtime); 60039444Smckusick /* 60139444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 60239444Smckusick * n_mtime fields. Check to see if it represents a special 60339444Smckusick * device, and if so, check for a possible alias. Once the 60439444Smckusick * correct vnode has been obtained, fill in the rest of the 60539444Smckusick * information. 60639444Smckusick */ 60738420Smckusick np = VTONFS(vp); 60839444Smckusick if (vp->v_type == VNON) { 60942244Smckusick if (type == VCHR && rdev == 0xffffffff) 61042244Smckusick vp->v_type = type = VFIFO; 61142244Smckusick else 61242244Smckusick vp->v_type = type; 61340295Smckusick if (vp->v_type == VFIFO) { 61440295Smckusick #ifdef FIFO 61540295Smckusick extern struct vnodeops fifo_nfsv2nodeops; 61640295Smckusick vp->v_op = &fifo_nfsv2nodeops; 61740295Smckusick #else 61840295Smckusick return (EOPNOTSUPP); 61940295Smckusick #endif /* FIFO */ 62040295Smckusick } 62139444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 62239444Smckusick vp->v_op = &spec_nfsv2nodeops; 62342244Smckusick if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 62439444Smckusick /* 62539444Smckusick * Reinitialize aliased node. 62639444Smckusick */ 62739444Smckusick np = VTONFS(nvp); 62839444Smckusick np->n_vnode = nvp; 62939907Smckusick np->n_flag = 0; 63039907Smckusick nfs_lock(nvp); 63139444Smckusick bcopy((caddr_t)&VTONFS(vp)->n_fh, 63239444Smckusick (caddr_t)&np->n_fh, NFSX_FH); 63339444Smckusick insque(np, nfs_hash(&np->n_fh)); 63439444Smckusick np->n_attrstamp = 0; 63539444Smckusick np->n_sillyrename = (struct sillyrename *)0; 63639444Smckusick /* 63739457Smckusick * Discard unneeded vnode and update actual one 63839444Smckusick */ 63939444Smckusick vput(vp); 64041902Smckusick *vpp = nvp; 64139444Smckusick } 64239444Smckusick } 64339444Smckusick np->n_mtime = mtime.tv_sec; 64439444Smckusick } 64538420Smckusick vap = &np->n_vattr; 64639444Smckusick vap->va_type = type; 64738884Smacklem vap->va_mode = nfstov_mode(fp->fa_mode); 64838884Smacklem vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 64938884Smacklem vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 65038884Smacklem vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 65138884Smacklem vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 65238884Smacklem if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) 65338884Smacklem np->n_size = vap->va_size; 65440642Smckusick vap->va_size_rsv = 0; 65538884Smacklem vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 65642244Smckusick vap->va_rdev = (dev_t)rdev; 65742244Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 65840642Smckusick vap->va_bytes_rsv = 0; 65942878Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 66038884Smacklem vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 66139755Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 66239755Smckusick vap->va_atime.tv_usec = 0; 66339755Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 66439444Smckusick vap->va_mtime = mtime; 66539755Smckusick vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 66639755Smckusick vap->va_ctime.tv_usec = 0; 66739755Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 66838420Smckusick np->n_attrstamp = time.tv_sec; 66938420Smckusick *dposp = dpos; 67038420Smckusick *mdp = md; 67138884Smacklem if (vaper != NULL) { 67238420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 67338884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 67438884Smacklem vaper->va_size = np->n_size; 67538884Smacklem } 67638420Smckusick return (0); 67738420Smckusick } 67838420Smckusick 67938420Smckusick /* 68038420Smckusick * Check the time stamp 68138420Smckusick * If the cache is valid, copy contents to *vap and return 0 68238420Smckusick * otherwise return an error 68338420Smckusick */ 68438420Smckusick nfs_getattrcache(vp, vap) 68538420Smckusick register struct vnode *vp; 68638420Smckusick struct vattr *vap; 68738420Smckusick { 68838420Smckusick register struct nfsnode *np; 68938420Smckusick 69038420Smckusick np = VTONFS(vp); 69138420Smckusick if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 69238420Smckusick nfsstats.attrcache_hits++; 69338420Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 69439361Smckusick if ((np->n_flag & NMODIFIED) == 0) 69539361Smckusick np->n_size = vap->va_size; 69639361Smckusick else if (np->n_size > vap->va_size) 69738884Smacklem vap->va_size = np->n_size; 69838420Smckusick return (0); 69938420Smckusick } else { 70038420Smckusick nfsstats.attrcache_misses++; 70138420Smckusick return (ENOENT); 70238420Smckusick } 70338420Smckusick } 70438420Smckusick 70538420Smckusick /* 70641902Smckusick * Set up nameidata for a namei() call and do it 70738420Smckusick */ 70838420Smckusick nfs_namei(ndp, fhp, len, mdp, dposp) 70938420Smckusick register struct nameidata *ndp; 71038420Smckusick fhandle_t *fhp; 71138420Smckusick int len; 71238420Smckusick struct mbuf **mdp; 71338420Smckusick caddr_t *dposp; 71438420Smckusick { 71538420Smckusick register int i, rem; 71638420Smckusick register struct mbuf *md; 71738420Smckusick register char *cp; 71841902Smckusick struct vnode *dp; 71938420Smckusick int flag; 72041902Smckusick int error; 72138420Smckusick 72242244Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) { 72342244Smckusick flag = ndp->ni_nameiop & OPFLAG; 72442244Smckusick /* 72542244Smckusick * Copy the name from the mbuf list to the d_name field of ndp 72642244Smckusick * and set the various ndp fields appropriately. 72742244Smckusick */ 72842244Smckusick cp = *dposp; 72942244Smckusick md = *mdp; 73042244Smckusick rem = mtod(md, caddr_t)+md->m_len-cp; 73142244Smckusick ndp->ni_hash = 0; 73242244Smckusick for (i = 0; i < len;) { 73342244Smckusick while (rem == 0) { 73442244Smckusick md = md->m_next; 73542244Smckusick if (md == NULL) 73642244Smckusick return (EBADRPC); 73742244Smckusick cp = mtod(md, caddr_t); 73842244Smckusick rem = md->m_len; 73942244Smckusick } 74042244Smckusick if (*cp == '\0' || *cp == '/') 74142244Smckusick return (EINVAL); 74242244Smckusick if (*cp & 0200) 74342244Smckusick if ((*cp&0377) == ('/'|0200) || flag != DELETE) 74442244Smckusick return (EINVAL); 74542244Smckusick ndp->ni_dent.d_name[i++] = *cp; 74642244Smckusick ndp->ni_hash += (unsigned char)*cp * i; 74742244Smckusick cp++; 74842244Smckusick rem--; 74938420Smckusick } 75042244Smckusick *mdp = md; 75142244Smckusick *dposp = cp; 75242244Smckusick len = nfsm_rndup(len)-len; 75342244Smckusick if (len > 0) { 75442244Smckusick if (rem < len) { 75542244Smckusick if (error = nfs_adv(mdp, dposp, len, rem)) 75642244Smckusick return (error); 75742244Smckusick } else 75842244Smckusick *dposp += len; 75942244Smckusick } 76042244Smckusick } else 76142244Smckusick i = len; 76238420Smckusick ndp->ni_namelen = i; 76338420Smckusick ndp->ni_dent.d_namlen = i; 76438420Smckusick ndp->ni_dent.d_name[i] = '\0'; 76542244Smckusick ndp->ni_segflg = UIO_SYSSPACE; 76638425Smckusick ndp->ni_pathlen = 1; 76741902Smckusick ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 76838420Smckusick ndp->ni_next = &ndp->ni_dent.d_name[i]; 76941902Smckusick ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF); 77038420Smckusick 77141902Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 77238420Smckusick return (error); 77338425Smckusick if (dp->v_type != VDIR) { 77441902Smckusick vrele(dp); 77538425Smckusick return (ENOTDIR); 77638425Smckusick } 77739345Smckusick /* 77839345Smckusick * Must set current directory here to avoid confusion in namei() 77939345Smckusick * called from rename() 78039345Smckusick */ 78138425Smckusick ndp->ni_cdir = dp; 78241398Smckusick ndp->ni_rdir = NULLVP; 78338420Smckusick 78438420Smckusick /* 78541902Smckusick * And call namei() to do the real work 78638420Smckusick */ 78741902Smckusick error = namei(ndp); 78841902Smckusick vrele(dp); 78938420Smckusick return (error); 79038420Smckusick } 79138420Smckusick 79238420Smckusick /* 79338420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 79438420Smckusick * boundary and only trims off the back end 79538420Smckusick */ 79638420Smckusick nfsm_adj(mp, len, nul) 79738420Smckusick struct mbuf *mp; 79838420Smckusick register int len; 79938420Smckusick int nul; 80038420Smckusick { 80138420Smckusick register struct mbuf *m; 80238420Smckusick register int count, i; 80338420Smckusick register char *cp; 80438420Smckusick 80538420Smckusick /* 80638420Smckusick * Trim from tail. Scan the mbuf chain, 80738420Smckusick * calculating its length and finding the last mbuf. 80838420Smckusick * If the adjustment only affects this mbuf, then just 80938420Smckusick * adjust and return. Otherwise, rescan and truncate 81038420Smckusick * after the remaining size. 81138420Smckusick */ 81238420Smckusick count = 0; 81338420Smckusick m = mp; 81438420Smckusick for (;;) { 81538420Smckusick count += m->m_len; 81638420Smckusick if (m->m_next == (struct mbuf *)0) 81738420Smckusick break; 81838420Smckusick m = m->m_next; 81938420Smckusick } 82038579Smckusick if (m->m_len > len) { 82138420Smckusick m->m_len -= len; 82238420Smckusick if (nul > 0) { 82338420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 82438420Smckusick for (i = 0; i < nul; i++) 82538420Smckusick *cp++ = '\0'; 82638420Smckusick } 82738420Smckusick return; 82838420Smckusick } 82938420Smckusick count -= len; 83038420Smckusick if (count < 0) 83138420Smckusick count = 0; 83238420Smckusick /* 83338420Smckusick * Correct length for chain is "count". 83438420Smckusick * Find the mbuf with last data, adjust its length, 83538420Smckusick * and toss data from remaining mbufs on chain. 83638420Smckusick */ 83738420Smckusick for (m = mp; m; m = m->m_next) { 83838420Smckusick if (m->m_len >= count) { 83938420Smckusick m->m_len = count; 84038420Smckusick if (nul > 0) { 84138420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 84238420Smckusick for (i = 0; i < nul; i++) 84338420Smckusick *cp++ = '\0'; 84438420Smckusick } 84538420Smckusick break; 84638420Smckusick } 84738420Smckusick count -= m->m_len; 84838420Smckusick } 84938420Smckusick while (m = m->m_next) 85038420Smckusick m->m_len = 0; 85138420Smckusick } 85238420Smckusick 85338420Smckusick /* 85438420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 85538420Smckusick * - look up fsid in mount list (if not found ret error) 85638420Smckusick * - check that it is exported 85738420Smckusick * - get vp by calling VFS_FHTOVP() macro 85838420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 85941902Smckusick * - if cred->cr_uid == 0 set it to m_exroot 86038420Smckusick */ 86138420Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred) 86238420Smckusick fhandle_t *fhp; 86338420Smckusick int lockflag; 86438420Smckusick struct vnode **vpp; 86538420Smckusick struct ucred *cred; 86638420Smckusick { 86738420Smckusick register struct mount *mp; 86838420Smckusick 86938420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 87038420Smckusick return (ESTALE); 87141398Smckusick if ((mp->mnt_flag & MNT_EXPORTED) == 0) 87238420Smckusick return (EACCES); 87338420Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 87438420Smckusick return (ESTALE); 87538420Smckusick if (cred->cr_uid == 0) 87641398Smckusick cred->cr_uid = mp->mnt_exroot; 87738420Smckusick if (!lockflag) 87838420Smckusick VOP_UNLOCK(*vpp); 87938420Smckusick return (0); 88038420Smckusick } 881