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 * 838420Smckusick * Redistribution and use in source and binary forms are permitted 938420Smckusick * provided that the above copyright notice and this paragraph are 1038420Smckusick * duplicated in all such forms and that any documentation, 1138420Smckusick * advertising materials, and other materials related to such 1238420Smckusick * distribution and use acknowledge that the software was developed 1338420Smckusick * by the University of California, Berkeley. The name of the 1438420Smckusick * University may not be used to endorse or promote products derived 1538420Smckusick * from this software without specific prior written permission. 1638420Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738420Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838420Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938420Smckusick * 20*43353Smckusick * @(#)nfs_subs.c 7.27 (Berkeley) 06/21/90 2138420Smckusick */ 2238420Smckusick 2338420Smckusick /* 2438420Smckusick * These functions support the macros and help fiddle mbuf chains for 2538420Smckusick * the nfs op functions. They do things like create the rpc header and 2638420Smckusick * copy data between mbuf chains and uio lists. 2738420Smckusick */ 2838420Smckusick #include "param.h" 2939345Smckusick #include "user.h" 3039345Smckusick #include "proc.h" 3140136Smckusick #include "systm.h" 3240136Smckusick #include "kernel.h" 3338420Smckusick #include "mount.h" 3438420Smckusick #include "file.h" 3538420Smckusick #include "vnode.h" 3640136Smckusick #include "mbuf.h" 3740136Smckusick #include "errno.h" 3838884Smacklem #include "map.h" 3938420Smckusick #include "rpcv2.h" 4038420Smckusick #include "nfsv2.h" 4138420Smckusick #include "nfsnode.h" 4238420Smckusick #include "nfs.h" 4338884Smacklem #include "nfsiom.h" 4438420Smckusick #include "xdr_subs.h" 4538420Smckusick #include "nfsm_subs.h" 4638420Smckusick 4738420Smckusick #define TRUE 1 4838420Smckusick #define FALSE 0 4938420Smckusick 5038420Smckusick /* 5138420Smckusick * Data items converted to xdr at startup, since they are constant 5238420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 5338420Smckusick */ 5438420Smckusick u_long nfs_procids[NFS_NPROCS]; 5538420Smckusick u_long nfs_xdrneg1; 5638420Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 5738420Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 5838420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 5938420Smckusick /* And other global data */ 6038420Smckusick static u_long *rpc_uidp = (u_long *)0; 6138420Smckusick static u_long nfs_xid = 1; 6238420Smckusick static char *rpc_unixauth; 6338420Smckusick extern long hostid; 6442244Smckusick enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 6541902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 6638884Smacklem extern struct map nfsmap[NFS_MSIZ]; 6741902Smckusick extern struct nfsreq nfsreqh; 6838420Smckusick 6938420Smckusick /* Function ret types */ 7038420Smckusick static char *nfs_unixauth(); 7138420Smckusick 7238420Smckusick /* 7338737Smckusick * Maximum number of groups passed through to NFS server. 7441902Smckusick * According to RFC1057 it should be 16. 7538737Smckusick * For release 3.X systems, the maximum value is 8. 7638737Smckusick * For release 4.X systems, the maximum value is 10. 7738737Smckusick */ 7838737Smckusick int numgrps = 8; 7938737Smckusick 8038737Smckusick /* 8138420Smckusick * Create the header for an rpc request packet 8238420Smckusick * The function nfs_unixauth() creates a unix style authorization string 8338420Smckusick * and returns a ptr to it. 8438420Smckusick * The hsiz is the size of the rest of the nfs request header. 8538420Smckusick * (just used to decide if a cluster is a good idea) 8639494Smckusick * nb: Note that the prog, vers and procid args are already in xdr byte order 8738420Smckusick */ 8839494Smckusick struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 8938420Smckusick u_long prog; 9038420Smckusick u_long vers; 9139494Smckusick u_long procid; 9238420Smckusick struct ucred *cred; 9338420Smckusick int hsiz; 9438420Smckusick caddr_t *bpos; 9538420Smckusick struct mbuf **mb; 9638420Smckusick u_long *retxid; 9738420Smckusick { 9838420Smckusick register struct mbuf *mreq, *m; 9938420Smckusick register u_long *p; 10038420Smckusick struct mbuf *m1; 10138420Smckusick char *ap; 10238420Smckusick int asiz, siz; 10338420Smckusick 10438420Smckusick NFSMGETHDR(mreq); 10538737Smckusick asiz = (((cred->cr_ngroups > numgrps) ? numgrps : cred->cr_ngroups)<<2); 10638425Smckusick #ifdef FILLINHOST 10738420Smckusick asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 10838425Smckusick #else 10938425Smckusick asiz += 9*NFSX_UNSIGNED; 11038425Smckusick #endif 11138420Smckusick 11238420Smckusick /* If we need a lot, alloc a cluster ?? */ 11338420Smckusick if ((asiz+hsiz+RPC_SIZ) > MHLEN) 11441902Smckusick MCLGET(mreq, M_WAIT); 11538420Smckusick mreq->m_len = NFSMSIZ(mreq); 11638420Smckusick siz = mreq->m_len; 11738420Smckusick m1 = mreq; 11838420Smckusick /* 11938420Smckusick * Alloc enough mbufs 12038420Smckusick * We do it now to avoid all sleeps after the call to nfs_unixauth() 12138420Smckusick */ 12238420Smckusick while ((asiz+RPC_SIZ) > siz) { 12338420Smckusick MGET(m, M_WAIT, MT_DATA); 12438420Smckusick m1->m_next = m; 12538420Smckusick m->m_len = MLEN; 12638420Smckusick siz += MLEN; 12738420Smckusick m1 = m; 12838420Smckusick } 12938420Smckusick p = mtod(mreq, u_long *); 13038420Smckusick *p++ = *retxid = txdr_unsigned(++nfs_xid); 13138420Smckusick *p++ = rpc_call; 13238420Smckusick *p++ = rpc_vers; 13338420Smckusick *p++ = prog; 13438420Smckusick *p++ = vers; 13539494Smckusick *p++ = procid; 13638420Smckusick 13738420Smckusick /* Now we can call nfs_unixauth() and copy it in */ 13838420Smckusick ap = nfs_unixauth(cred); 13938420Smckusick m = mreq; 14038420Smckusick siz = m->m_len-RPC_SIZ; 14138420Smckusick if (asiz <= siz) { 14238420Smckusick bcopy(ap, (caddr_t)p, asiz); 14338420Smckusick m->m_len = asiz+RPC_SIZ; 14438420Smckusick } else { 14538420Smckusick bcopy(ap, (caddr_t)p, siz); 14638420Smckusick ap += siz; 14738420Smckusick asiz -= siz; 14838420Smckusick while (asiz > 0) { 14938420Smckusick siz = (asiz > MLEN) ? MLEN : asiz; 15038420Smckusick m = m->m_next; 15138420Smckusick bcopy(ap, mtod(m, caddr_t), siz); 15238420Smckusick m->m_len = siz; 15338420Smckusick asiz -= siz; 15438420Smckusick ap += siz; 15538420Smckusick } 15638420Smckusick } 15738420Smckusick 15838420Smckusick /* Finally, return values */ 15938420Smckusick *mb = m; 16038420Smckusick *bpos = mtod(m, caddr_t)+m->m_len; 16138420Smckusick return (mreq); 16238420Smckusick } 16338420Smckusick 16438420Smckusick /* 16538420Smckusick * copies mbuf chain to the uio scatter/gather list 16638420Smckusick */ 16738420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 16838420Smckusick struct mbuf **mrep; 169*43353Smckusick register struct uio *uiop; 17038420Smckusick int siz; 17138420Smckusick caddr_t *dpos; 17238420Smckusick { 173*43353Smckusick register char *mbufcp, *uiocp; 17438420Smckusick register int xfer, left, len; 17538420Smckusick register struct mbuf *mp; 17638420Smckusick long uiosiz, rem; 17741902Smckusick int error = 0; 17838420Smckusick 17938420Smckusick mp = *mrep; 18038420Smckusick mbufcp = *dpos; 18138420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 18238420Smckusick rem = nfsm_rndup(siz)-siz; 18338420Smckusick while (siz > 0) { 18438420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 18541902Smckusick return (EFBIG); 18638420Smckusick left = uiop->uio_iov->iov_len; 18738420Smckusick uiocp = uiop->uio_iov->iov_base; 18838420Smckusick if (left > siz) 18938420Smckusick left = siz; 19038420Smckusick uiosiz = left; 19138420Smckusick while (left > 0) { 19238420Smckusick while (len == 0) { 19338420Smckusick mp = mp->m_next; 19438420Smckusick if (mp == NULL) 19538420Smckusick return (EBADRPC); 19638420Smckusick mbufcp = mtod(mp, caddr_t); 19738420Smckusick len = mp->m_len; 19838420Smckusick } 19938420Smckusick xfer = (left > len) ? len : left; 20038420Smckusick #ifdef notdef 20138420Smckusick /* Not Yet.. */ 20238420Smckusick if (uiop->uio_iov->iov_op != NULL) 20338420Smckusick (*(uiop->uio_iov->iov_op)) 20438420Smckusick (mbufcp, uiocp, xfer); 20538420Smckusick else 20638420Smckusick #endif 20738420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 20838420Smckusick bcopy(mbufcp, uiocp, xfer); 20938420Smckusick else 21038420Smckusick copyout(mbufcp, uiocp, xfer); 21138420Smckusick left -= xfer; 21238420Smckusick len -= xfer; 21338420Smckusick mbufcp += xfer; 21438420Smckusick uiocp += xfer; 21539585Smckusick uiop->uio_offset += xfer; 21638420Smckusick uiop->uio_resid -= xfer; 21738420Smckusick } 21838420Smckusick if (uiop->uio_iov->iov_len <= siz) { 21938420Smckusick uiop->uio_iovcnt--; 22038420Smckusick uiop->uio_iov++; 22138420Smckusick } else { 22238420Smckusick uiop->uio_iov->iov_base += uiosiz; 22338420Smckusick uiop->uio_iov->iov_len -= uiosiz; 22438420Smckusick } 22538420Smckusick siz -= uiosiz; 22638420Smckusick } 22738420Smckusick *dpos = mbufcp; 22838420Smckusick *mrep = mp; 22941902Smckusick if (rem > 0) { 23041902Smckusick if (len < rem) 23141902Smckusick error = nfs_adv(mrep, dpos, rem, len); 23241902Smckusick else 23341902Smckusick *dpos += rem; 23441902Smckusick } 23541902Smckusick return (error); 23638420Smckusick } 23738420Smckusick 23838420Smckusick /* 23938420Smckusick * copies a uio scatter/gather list to an mbuf chain... 24038420Smckusick */ 24138420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 24238420Smckusick register struct uio *uiop; 24338420Smckusick struct mbuf **mq; 24438420Smckusick int siz; 24538420Smckusick caddr_t *bpos; 24638420Smckusick { 247*43353Smckusick register char *uiocp; 248*43353Smckusick register struct mbuf *mp, *mp2; 249*43353Smckusick register int xfer, left, len; 250*43353Smckusick int uiosiz, clflg, rem; 251*43353Smckusick char *cp; 25238420Smckusick 25338420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 25438420Smckusick clflg = 1; 25538420Smckusick else 25638420Smckusick clflg = 0; 25738420Smckusick rem = nfsm_rndup(siz)-siz; 25838420Smckusick mp2 = *mq; 25938420Smckusick while (siz > 0) { 26038420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 26141902Smckusick return (EINVAL); 26238420Smckusick left = uiop->uio_iov->iov_len; 26338420Smckusick uiocp = uiop->uio_iov->iov_base; 26438420Smckusick if (left > siz) 26538420Smckusick left = siz; 26638420Smckusick uiosiz = left; 26738420Smckusick while (left > 0) { 26838420Smckusick MGET(mp, M_WAIT, MT_DATA); 26938420Smckusick if (clflg) 27041902Smckusick MCLGET(mp, M_WAIT); 27138420Smckusick mp->m_len = NFSMSIZ(mp); 27238420Smckusick mp2->m_next = mp; 27338420Smckusick mp2 = mp; 27438420Smckusick xfer = (left > mp->m_len) ? mp->m_len : left; 27538420Smckusick #ifdef notdef 27638420Smckusick /* Not Yet.. */ 27738420Smckusick if (uiop->uio_iov->iov_op != NULL) 27838420Smckusick (*(uiop->uio_iov->iov_op)) 27938420Smckusick (uiocp, mtod(mp, caddr_t), xfer); 28038420Smckusick else 28138420Smckusick #endif 28238420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 28338420Smckusick bcopy(uiocp, mtod(mp, caddr_t), xfer); 28438420Smckusick else 28538420Smckusick copyin(uiocp, mtod(mp, caddr_t), xfer); 28638420Smckusick len = mp->m_len; 28738420Smckusick mp->m_len = xfer; 28838420Smckusick left -= xfer; 28938420Smckusick uiocp += xfer; 29039585Smckusick uiop->uio_offset += xfer; 29138420Smckusick uiop->uio_resid -= xfer; 29238420Smckusick } 29338420Smckusick if (uiop->uio_iov->iov_len <= siz) { 29438420Smckusick uiop->uio_iovcnt--; 29538420Smckusick uiop->uio_iov++; 29638420Smckusick } else { 29738420Smckusick uiop->uio_iov->iov_base += uiosiz; 29838420Smckusick uiop->uio_iov->iov_len -= uiosiz; 29938420Smckusick } 30038420Smckusick siz -= uiosiz; 30138420Smckusick } 30238420Smckusick if (rem > 0) { 30338420Smckusick if (rem > (len-mp->m_len)) { 30438420Smckusick MGET(mp, M_WAIT, MT_DATA); 30538420Smckusick mp->m_len = 0; 30638420Smckusick mp2->m_next = mp; 30738420Smckusick } 30838420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 30938420Smckusick for (left = 0; left < rem; left++) 31038420Smckusick *cp++ = '\0'; 31138420Smckusick mp->m_len += rem; 31238420Smckusick *bpos = cp; 31338420Smckusick } else 31438420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 31538420Smckusick *mq = mp; 31641902Smckusick return (0); 31738420Smckusick } 31838420Smckusick 31938420Smckusick /* 32038420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 32138420Smckusick * pointed to by returned val. 32238420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 32338420Smckusick * This is used by the macros nfsm_disect and nfsm_disecton for tough 32438420Smckusick * cases. (The macros use the vars. dpos and dpos2) 32538420Smckusick */ 32638420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 32738420Smckusick struct mbuf **mdp; 32838420Smckusick caddr_t *dposp; 32938420Smckusick int siz; 33038420Smckusick int left; 33138420Smckusick int updateflg; 33238420Smckusick caddr_t *cp2; 33338420Smckusick { 33438420Smckusick register struct mbuf *mp, *mp2; 33538420Smckusick register int siz2, xfer; 33638420Smckusick register caddr_t p; 33738420Smckusick 33838420Smckusick mp = *mdp; 33938420Smckusick while (left == 0) { 34038420Smckusick *mdp = mp = mp->m_next; 34138420Smckusick if (mp == NULL) 34241902Smckusick return (EBADRPC); 34338420Smckusick left = mp->m_len; 34438420Smckusick *dposp = mtod(mp, caddr_t); 34538420Smckusick } 34638420Smckusick if (left >= siz) { 34738420Smckusick *cp2 = *dposp; 34838420Smckusick *dposp += siz; 34938420Smckusick } else if (mp->m_next == NULL) { 35041902Smckusick return (EBADRPC); 35141902Smckusick } else if (siz > MHLEN) { 35238420Smckusick panic("nfs S too big"); 35338420Smckusick } else { 35438420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 35538420Smckusick if (updateflg) { 35638420Smckusick NFSMINOFF(mp); 35738420Smckusick } else { 35838420Smckusick MGET(mp2, M_WAIT, MT_DATA); 35938420Smckusick mp2->m_next = mp->m_next; 36038420Smckusick mp->m_next = mp2; 36138420Smckusick mp->m_len -= left; 36238420Smckusick mp = mp2; 36338420Smckusick } 36438420Smckusick *cp2 = p = mtod(mp, caddr_t); 36538420Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 36638420Smckusick siz2 = siz-left; 36738420Smckusick p += left; 36838420Smckusick mp2 = mp->m_next; 36941902Smckusick /* Loop around copying up the siz2 bytes */ 37038420Smckusick while (siz2 > 0) { 37138420Smckusick if (mp2 == NULL) 37238420Smckusick return (EBADRPC); 37338420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 37441902Smckusick if (xfer > 0) { 37541902Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 37641902Smckusick NFSMADV(mp2, xfer); 37741902Smckusick mp2->m_len -= xfer; 37841902Smckusick p += xfer; 37941902Smckusick siz2 -= xfer; 38041902Smckusick } 38138420Smckusick if (siz2 > 0) 38238420Smckusick mp2 = mp2->m_next; 38338420Smckusick } 38438420Smckusick mp->m_len = siz; 38538420Smckusick *mdp = mp2; 38638420Smckusick *dposp = mtod(mp2, caddr_t); 38738420Smckusick } 38839494Smckusick return (0); 38938420Smckusick } 39038420Smckusick 39138420Smckusick /* 39241902Smckusick * Advance the position in the mbuf chain. 39338420Smckusick */ 39438420Smckusick nfs_adv(mdp, dposp, offs, left) 39538420Smckusick struct mbuf **mdp; 39638420Smckusick caddr_t *dposp; 39738420Smckusick int offs; 39838420Smckusick int left; 39938420Smckusick { 40038420Smckusick register struct mbuf *m; 40138420Smckusick register int s; 40238420Smckusick 40338420Smckusick m = *mdp; 40438420Smckusick s = left; 40538420Smckusick while (s < offs) { 40638420Smckusick offs -= s; 40738420Smckusick m = m->m_next; 40838420Smckusick if (m == NULL) 40941902Smckusick return (EBADRPC); 41038420Smckusick s = m->m_len; 41138420Smckusick } 41238420Smckusick *mdp = m; 41338420Smckusick *dposp = mtod(m, caddr_t)+offs; 41441902Smckusick return (0); 41538420Smckusick } 41638420Smckusick 41738420Smckusick /* 41838420Smckusick * Copy a string into mbufs for the hard cases... 41938420Smckusick */ 42038420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 42138420Smckusick struct mbuf **mb; 42238420Smckusick char **bpos; 42338420Smckusick char *cp; 42438420Smckusick long siz; 42538420Smckusick { 42638420Smckusick register struct mbuf *m1, *m2; 42738420Smckusick long left, xfer, len, tlen; 42838420Smckusick u_long *p; 42938420Smckusick int putsize; 43038420Smckusick 43138420Smckusick putsize = 1; 43238420Smckusick m2 = *mb; 43338420Smckusick left = NFSMSIZ(m2)-m2->m_len; 43438420Smckusick if (left > 0) { 43538420Smckusick p = ((u_long *)(*bpos)); 43638420Smckusick *p++ = txdr_unsigned(siz); 43738420Smckusick putsize = 0; 43838420Smckusick left -= NFSX_UNSIGNED; 43938420Smckusick m2->m_len += NFSX_UNSIGNED; 44038420Smckusick if (left > 0) { 44138420Smckusick bcopy(cp, (caddr_t) p, left); 44238420Smckusick siz -= left; 44338420Smckusick cp += left; 44438420Smckusick m2->m_len += left; 44538420Smckusick left = 0; 44638420Smckusick } 44738420Smckusick } 44838420Smckusick /* Loop arround adding mbufs */ 44938420Smckusick while (siz > 0) { 45038420Smckusick MGET(m1, M_WAIT, MT_DATA); 45138420Smckusick if (siz > MLEN) 45241902Smckusick MCLGET(m1, M_WAIT); 45338420Smckusick m1->m_len = NFSMSIZ(m1); 45438420Smckusick m2->m_next = m1; 45538420Smckusick m2 = m1; 45638420Smckusick p = mtod(m1, u_long *); 45738420Smckusick tlen = 0; 45838420Smckusick if (putsize) { 45938420Smckusick *p++ = txdr_unsigned(siz); 46038420Smckusick m1->m_len -= NFSX_UNSIGNED; 46138420Smckusick tlen = NFSX_UNSIGNED; 46238420Smckusick putsize = 0; 46338420Smckusick } 46438420Smckusick if (siz < m1->m_len) { 46538420Smckusick len = nfsm_rndup(siz); 46638420Smckusick xfer = siz; 46738420Smckusick if (xfer < len) 46838420Smckusick *(p+(xfer>>2)) = 0; 46938420Smckusick } else { 47038420Smckusick xfer = len = m1->m_len; 47138420Smckusick } 47238420Smckusick bcopy(cp, (caddr_t) p, xfer); 47338420Smckusick m1->m_len = len+tlen; 47438420Smckusick siz -= xfer; 47538420Smckusick cp += xfer; 47638420Smckusick } 47738420Smckusick *mb = m1; 47838420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 47941902Smckusick return (0); 48038420Smckusick } 48138420Smckusick 48238420Smckusick /* 48338420Smckusick * Called once to initialize data structures... 48438420Smckusick */ 48539444Smckusick nfs_init() 48638420Smckusick { 48738420Smckusick register int i; 48838420Smckusick 48938420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 49038420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 49138420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 49238420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 49338420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 49438420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 49538420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 49638420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 49738420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 49838420Smckusick nfs_true = txdr_unsigned(TRUE); 49938420Smckusick nfs_false = txdr_unsigned(FALSE); 50038420Smckusick /* Loop thru nfs procids */ 50138420Smckusick for (i = 0; i < NFS_NPROCS; i++) 50238420Smckusick nfs_procids[i] = txdr_unsigned(i); 50339345Smckusick /* Ensure async daemons disabled */ 50441902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 50539345Smckusick nfs_iodwant[i] = (struct proc *)0; 50638420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 50738420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 50839755Smckusick nfsrv_initcache(); /* Init the server request cache */ 50938884Smacklem rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 51041902Smckusick 51141902Smckusick /* 51241902Smckusick * Initialize reply list and start timer 51341902Smckusick */ 51441902Smckusick nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 51538420Smckusick nfs_timer(); 51638420Smckusick } 51738420Smckusick 51838420Smckusick /* 51938420Smckusick * Fill in the rest of the rpc_unixauth and return it 52038420Smckusick */ 52138420Smckusick static char *nfs_unixauth(cr) 52238420Smckusick register struct ucred *cr; 52338420Smckusick { 52438420Smckusick register u_long *p; 52538420Smckusick register int i; 52638420Smckusick int ngr; 52738420Smckusick 52838420Smckusick /* Maybe someday there should be a cache of AUTH_SHORT's */ 52938420Smckusick if ((p = rpc_uidp) == NULL) { 53038425Smckusick #ifdef FILLINHOST 53138420Smckusick i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); 53238425Smckusick #else 53338425Smckusick i = 19*NFSX_UNSIGNED; 53438425Smckusick #endif 53538420Smckusick MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 53638420Smckusick bzero((caddr_t)p, i); 53738420Smckusick rpc_unixauth = (caddr_t)p; 53838420Smckusick *p++ = txdr_unsigned(RPCAUTH_UNIX); 53938420Smckusick p++; /* Fill in size later */ 54038420Smckusick *p++ = hostid; 54138425Smckusick #ifdef FILLINHOST 54238420Smckusick *p++ = txdr_unsigned(hostnamelen); 54338420Smckusick i = nfsm_rndup(hostnamelen); 54438420Smckusick bcopy(hostname, (caddr_t)p, hostnamelen); 54538420Smckusick p += (i>>2); 54638425Smckusick #else 54738425Smckusick *p++ = 0; 54838425Smckusick #endif 54938420Smckusick rpc_uidp = p; 55038420Smckusick } 55138420Smckusick *p++ = txdr_unsigned(cr->cr_uid); 55238420Smckusick *p++ = txdr_unsigned(cr->cr_groups[0]); 55338737Smckusick ngr = (cr->cr_ngroups > numgrps) ? numgrps : cr->cr_ngroups; 55438420Smckusick *p++ = txdr_unsigned(ngr); 55538420Smckusick for (i = 0; i < ngr; i++) 55638420Smckusick *p++ = txdr_unsigned(cr->cr_groups[i]); 55738420Smckusick /* And add the AUTH_NULL */ 55838420Smckusick *p++ = 0; 55938420Smckusick *p = 0; 56038420Smckusick i = (((caddr_t)p)-rpc_unixauth)-12; 56138420Smckusick p = (u_long *)(rpc_unixauth+4); 56238420Smckusick *p = txdr_unsigned(i); 56341902Smckusick return (rpc_unixauth); 56438420Smckusick } 56538420Smckusick 56638420Smckusick /* 56738420Smckusick * Attribute cache routines. 56838420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 56938420Smckusick * that are on the mbuf list 57038420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 57138420Smckusick * error otherwise 57238420Smckusick */ 57338420Smckusick 57438420Smckusick /* 57539444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 57638420Smckusick * the values on the mbuf list and 57738420Smckusick * Iff vap not NULL 57838420Smckusick * copy the attributes to *vaper 57938420Smckusick */ 58039457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 58139457Smckusick struct vnode **vpp; 58238420Smckusick struct mbuf **mdp; 58338420Smckusick caddr_t *dposp; 58438420Smckusick struct vattr *vaper; 58538420Smckusick { 58639457Smckusick register struct vnode *vp = *vpp; 58738420Smckusick register struct vattr *vap; 58838884Smacklem register struct nfsv2_fattr *fp; 58939444Smckusick extern struct vnodeops spec_nfsv2nodeops; 59039457Smckusick register struct nfsnode *np; 59139494Smckusick register long t1; 59239494Smckusick caddr_t dpos, cp2; 59339494Smckusick int error = 0; 59439494Smckusick struct mbuf *md; 59539444Smckusick enum vtype type; 59642244Smckusick long rdev; 59739444Smckusick struct timeval mtime; 59839444Smckusick struct vnode *nvp; 59938420Smckusick 60038420Smckusick md = *mdp; 60138420Smckusick dpos = *dposp; 60238420Smckusick t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 60338420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 60438420Smckusick return (error); 60538884Smacklem fp = (struct nfsv2_fattr *)cp2; 60639444Smckusick type = nfstov_type(fp->fa_type); 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 /* 63439444Smckusick * Reinitialize aliased node. 63539444Smckusick */ 63639444Smckusick np = VTONFS(nvp); 63739444Smckusick np->n_vnode = nvp; 63839907Smckusick np->n_flag = 0; 63939907Smckusick nfs_lock(nvp); 64039444Smckusick bcopy((caddr_t)&VTONFS(vp)->n_fh, 64139444Smckusick (caddr_t)&np->n_fh, NFSX_FH); 64239444Smckusick insque(np, nfs_hash(&np->n_fh)); 64339444Smckusick np->n_attrstamp = 0; 64439444Smckusick np->n_sillyrename = (struct sillyrename *)0; 64539444Smckusick /* 64639457Smckusick * Discard unneeded vnode and update actual one 64739444Smckusick */ 64839444Smckusick vput(vp); 64941902Smckusick *vpp = nvp; 65039444Smckusick } 65139444Smckusick } 65239444Smckusick np->n_mtime = mtime.tv_sec; 65339444Smckusick } 65438420Smckusick vap = &np->n_vattr; 65539444Smckusick vap->va_type = type; 65638884Smacklem vap->va_mode = nfstov_mode(fp->fa_mode); 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); 66138884Smacklem if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) 66238884Smacklem np->n_size = vap->va_size; 66340642Smckusick vap->va_size_rsv = 0; 66438884Smacklem vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 66542244Smckusick vap->va_rdev = (dev_t)rdev; 66642244Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 66740642Smckusick vap->va_bytes_rsv = 0; 66842878Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 66938884Smacklem vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 67039755Smckusick vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 67139755Smckusick vap->va_atime.tv_usec = 0; 67239755Smckusick vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 67339444Smckusick vap->va_mtime = mtime; 67439755Smckusick vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 67539755Smckusick vap->va_ctime.tv_usec = 0; 67639755Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 67738420Smckusick np->n_attrstamp = time.tv_sec; 67838420Smckusick *dposp = dpos; 67938420Smckusick *mdp = md; 68038884Smacklem if (vaper != NULL) { 68138420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 68238884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 68338884Smacklem vaper->va_size = np->n_size; 68438884Smacklem } 68538420Smckusick return (0); 68638420Smckusick } 68738420Smckusick 68838420Smckusick /* 68938420Smckusick * Check the time stamp 69038420Smckusick * If the cache is valid, copy contents to *vap and return 0 69138420Smckusick * otherwise return an error 69238420Smckusick */ 69338420Smckusick nfs_getattrcache(vp, vap) 69438420Smckusick register struct vnode *vp; 69538420Smckusick struct vattr *vap; 69638420Smckusick { 69738420Smckusick register struct nfsnode *np; 69838420Smckusick 69938420Smckusick np = VTONFS(vp); 70038420Smckusick if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 70138420Smckusick nfsstats.attrcache_hits++; 70238420Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 70339361Smckusick if ((np->n_flag & NMODIFIED) == 0) 70439361Smckusick np->n_size = vap->va_size; 70539361Smckusick 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; 72741902Smckusick struct vnode *dp; 72838420Smckusick int flag; 72941902Smckusick int error; 73038420Smckusick 73142244Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) { 73242244Smckusick flag = ndp->ni_nameiop & OPFLAG; 73342244Smckusick /* 73442244Smckusick * Copy the name from the mbuf list to the d_name field of ndp 73542244Smckusick * and set the various ndp fields appropriately. 73642244Smckusick */ 73742244Smckusick cp = *dposp; 73842244Smckusick md = *mdp; 73942244Smckusick rem = mtod(md, caddr_t)+md->m_len-cp; 74042244Smckusick ndp->ni_hash = 0; 74142244Smckusick for (i = 0; i < len;) { 74242244Smckusick while (rem == 0) { 74342244Smckusick md = md->m_next; 74442244Smckusick if (md == NULL) 74542244Smckusick return (EBADRPC); 74642244Smckusick cp = mtod(md, caddr_t); 74742244Smckusick rem = md->m_len; 74842244Smckusick } 74942244Smckusick if (*cp == '\0' || *cp == '/') 75042244Smckusick return (EINVAL); 75142244Smckusick if (*cp & 0200) 75242244Smckusick if ((*cp&0377) == ('/'|0200) || flag != DELETE) 75342244Smckusick return (EINVAL); 75442244Smckusick ndp->ni_dent.d_name[i++] = *cp; 75542244Smckusick ndp->ni_hash += (unsigned char)*cp * i; 75642244Smckusick cp++; 75742244Smckusick rem--; 75838420Smckusick } 75942244Smckusick *mdp = md; 76042244Smckusick *dposp = cp; 76142244Smckusick len = nfsm_rndup(len)-len; 76242244Smckusick if (len > 0) { 76342244Smckusick if (rem < len) { 76442244Smckusick if (error = nfs_adv(mdp, dposp, len, rem)) 76542244Smckusick return (error); 76642244Smckusick } else 76742244Smckusick *dposp += len; 76842244Smckusick } 76942244Smckusick } else 77042244Smckusick i = len; 77138420Smckusick ndp->ni_namelen = i; 77238420Smckusick ndp->ni_dent.d_namlen = i; 77338420Smckusick ndp->ni_dent.d_name[i] = '\0'; 77442244Smckusick ndp->ni_segflg = UIO_SYSSPACE; 77538425Smckusick ndp->ni_pathlen = 1; 77641902Smckusick ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 77738420Smckusick ndp->ni_next = &ndp->ni_dent.d_name[i]; 77841902Smckusick ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF); 77938420Smckusick 78041902Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 78138420Smckusick return (error); 78238425Smckusick if (dp->v_type != VDIR) { 78341902Smckusick vrele(dp); 78438425Smckusick return (ENOTDIR); 78538425Smckusick } 78639345Smckusick /* 78739345Smckusick * Must set current directory here to avoid confusion in namei() 78839345Smckusick * called from rename() 78939345Smckusick */ 79038425Smckusick ndp->ni_cdir = dp; 79141398Smckusick ndp->ni_rdir = NULLVP; 79238420Smckusick 79338420Smckusick /* 79441902Smckusick * And call namei() to do the real work 79538420Smckusick */ 79641902Smckusick error = namei(ndp); 79741902Smckusick vrele(dp); 79838420Smckusick return (error); 79938420Smckusick } 80038420Smckusick 80138420Smckusick /* 80238420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 80338420Smckusick * boundary and only trims off the back end 80438420Smckusick */ 80538420Smckusick nfsm_adj(mp, len, nul) 80638420Smckusick struct mbuf *mp; 80738420Smckusick register int len; 80838420Smckusick int nul; 80938420Smckusick { 81038420Smckusick register struct mbuf *m; 81138420Smckusick register int count, i; 81238420Smckusick register char *cp; 81338420Smckusick 81438420Smckusick /* 81538420Smckusick * Trim from tail. Scan the mbuf chain, 81638420Smckusick * calculating its length and finding the last mbuf. 81738420Smckusick * If the adjustment only affects this mbuf, then just 81838420Smckusick * adjust and return. Otherwise, rescan and truncate 81938420Smckusick * after the remaining size. 82038420Smckusick */ 82138420Smckusick count = 0; 82238420Smckusick m = mp; 82338420Smckusick for (;;) { 82438420Smckusick count += m->m_len; 82538420Smckusick if (m->m_next == (struct mbuf *)0) 82638420Smckusick break; 82738420Smckusick m = m->m_next; 82838420Smckusick } 82938579Smckusick if (m->m_len > len) { 83038420Smckusick m->m_len -= len; 83138420Smckusick if (nul > 0) { 83238420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 83338420Smckusick for (i = 0; i < nul; i++) 83438420Smckusick *cp++ = '\0'; 83538420Smckusick } 83638420Smckusick return; 83738420Smckusick } 83838420Smckusick count -= len; 83938420Smckusick if (count < 0) 84038420Smckusick count = 0; 84138420Smckusick /* 84238420Smckusick * Correct length for chain is "count". 84338420Smckusick * Find the mbuf with last data, adjust its length, 84438420Smckusick * and toss data from remaining mbufs on chain. 84538420Smckusick */ 84638420Smckusick for (m = mp; m; m = m->m_next) { 84738420Smckusick if (m->m_len >= count) { 84838420Smckusick m->m_len = count; 84938420Smckusick if (nul > 0) { 85038420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 85138420Smckusick for (i = 0; i < nul; i++) 85238420Smckusick *cp++ = '\0'; 85338420Smckusick } 85438420Smckusick break; 85538420Smckusick } 85638420Smckusick count -= m->m_len; 85738420Smckusick } 85838420Smckusick while (m = m->m_next) 85938420Smckusick m->m_len = 0; 86038420Smckusick } 86138420Smckusick 86238420Smckusick /* 86338420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 86438420Smckusick * - look up fsid in mount list (if not found ret error) 86538420Smckusick * - check that it is exported 86638420Smckusick * - get vp by calling VFS_FHTOVP() macro 86738420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 86841902Smckusick * - if cred->cr_uid == 0 set it to m_exroot 86938420Smckusick */ 87038420Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred) 87138420Smckusick fhandle_t *fhp; 87238420Smckusick int lockflag; 87338420Smckusick struct vnode **vpp; 87438420Smckusick struct ucred *cred; 87538420Smckusick { 87638420Smckusick register struct mount *mp; 87738420Smckusick 87838420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 87938420Smckusick return (ESTALE); 88041398Smckusick if ((mp->mnt_flag & MNT_EXPORTED) == 0) 88138420Smckusick return (EACCES); 88238420Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 88338420Smckusick return (ESTALE); 88438420Smckusick if (cred->cr_uid == 0) 88541398Smckusick cred->cr_uid = mp->mnt_exroot; 88638420Smckusick if (!lockflag) 88738420Smckusick VOP_UNLOCK(*vpp); 88838420Smckusick return (0); 88938420Smckusick } 890