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*38421Smckusick * @(#)nfs_subs.c 7.2 (Berkeley) 07/05/89 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 "strings.h" 2938420Smckusick #include "types.h" 3038420Smckusick #include "param.h" 3138420Smckusick #include "mount.h" 3238420Smckusick #include "dir.h" 3338420Smckusick #include "time.h" 3438420Smckusick #include "errno.h" 3538420Smckusick #include "kernel.h" 3638420Smckusick #include "malloc.h" 3738420Smckusick #include "mbuf.h" 3838420Smckusick #include "file.h" 3938420Smckusick #include "vnode.h" 4038420Smckusick #include "uio.h" 4138420Smckusick #include "namei.h" 4238420Smckusick #include "ucred.h" 4338420Smckusick #include "rpcv2.h" 4438420Smckusick #include "nfsv2.h" 4538420Smckusick #include "nfsnode.h" 4638420Smckusick #include "nfs.h" 4738420Smckusick #include "xdr_subs.h" 4838420Smckusick #include "nfsm_subs.h" 4938420Smckusick 5038420Smckusick #define TRUE 1 5138420Smckusick #define FALSE 0 5238420Smckusick 5338420Smckusick /* 5438420Smckusick * Data items converted to xdr at startup, since they are constant 5538420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 5638420Smckusick */ 5738420Smckusick u_long nfs_procids[NFS_NPROCS]; 5838420Smckusick u_long nfs_xdrneg1; 5938420Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 6038420Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 6138420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 6238420Smckusick /* And other global data */ 6338420Smckusick static u_long *rpc_uidp = (u_long *)0; 6438420Smckusick static u_long nfs_xid = 1; 6538420Smckusick static char *rpc_unixauth; 6638420Smckusick extern long hostid; 6738420Smckusick extern enum vtype v_type[NFLNK+1]; 6838420Smckusick 6938420Smckusick /* Function ret types */ 7038420Smckusick static char *nfs_unixauth(); 7138420Smckusick 7238420Smckusick /* 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) 7838420Smckusick * nb: Note that the prog, vers and proc args are already in xdr byte order 7938420Smckusick */ 8038420Smckusick struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid) 8138420Smckusick u_long prog; 8238420Smckusick u_long vers; 8338420Smckusick u_long proc; 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); 9738420Smckusick asiz = (((cred->cr_ngroups > 10) ? 10 : cred->cr_ngroups)<<2); 9838420Smckusick asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 9938420Smckusick 10038420Smckusick /* If we need a lot, alloc a cluster ?? */ 10138420Smckusick if ((asiz+hsiz+RPC_SIZ) > MHLEN) 10238420Smckusick NFSMCLGET(mreq, M_WAIT); 10338420Smckusick mreq->m_len = NFSMSIZ(mreq); 10438420Smckusick siz = mreq->m_len; 10538420Smckusick m1 = mreq; 10638420Smckusick /* 10738420Smckusick * Alloc enough mbufs 10838420Smckusick * We do it now to avoid all sleeps after the call to nfs_unixauth() 10938420Smckusick */ 11038420Smckusick while ((asiz+RPC_SIZ) > siz) { 11138420Smckusick MGET(m, M_WAIT, MT_DATA); 11238420Smckusick m1->m_next = m; 11338420Smckusick m->m_len = MLEN; 11438420Smckusick siz += MLEN; 11538420Smckusick m1 = m; 11638420Smckusick } 11738420Smckusick p = mtod(mreq, u_long *); 11838420Smckusick *p++ = *retxid = txdr_unsigned(++nfs_xid); 11938420Smckusick *p++ = rpc_call; 12038420Smckusick *p++ = rpc_vers; 12138420Smckusick *p++ = prog; 12238420Smckusick *p++ = vers; 12338420Smckusick *p++ = proc; 12438420Smckusick 12538420Smckusick /* Now we can call nfs_unixauth() and copy it in */ 12638420Smckusick ap = nfs_unixauth(cred); 12738420Smckusick m = mreq; 12838420Smckusick siz = m->m_len-RPC_SIZ; 12938420Smckusick if (asiz <= siz) { 13038420Smckusick bcopy(ap, (caddr_t)p, asiz); 13138420Smckusick m->m_len = asiz+RPC_SIZ; 13238420Smckusick } else { 13338420Smckusick bcopy(ap, (caddr_t)p, siz); 13438420Smckusick ap += siz; 13538420Smckusick asiz -= siz; 13638420Smckusick while (asiz > 0) { 13738420Smckusick siz = (asiz > MLEN) ? MLEN : asiz; 13838420Smckusick m = m->m_next; 13938420Smckusick bcopy(ap, mtod(m, caddr_t), siz); 14038420Smckusick m->m_len = siz; 14138420Smckusick asiz -= siz; 14238420Smckusick ap += siz; 14338420Smckusick } 14438420Smckusick } 14538420Smckusick 14638420Smckusick /* Finally, return values */ 14738420Smckusick *mb = m; 14838420Smckusick *bpos = mtod(m, caddr_t)+m->m_len; 14938420Smckusick return (mreq); 15038420Smckusick } 15138420Smckusick 15238420Smckusick /* 15338420Smckusick * copies mbuf chain to the uio scatter/gather list 15438420Smckusick */ 15538420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 15638420Smckusick struct mbuf **mrep; 15738420Smckusick struct uio *uiop; 15838420Smckusick int siz; 15938420Smckusick caddr_t *dpos; 16038420Smckusick { 16138420Smckusick register int xfer, left, len; 16238420Smckusick register struct mbuf *mp; 16338420Smckusick register char *mbufcp, *uiocp; 16438420Smckusick long uiosiz, rem; 16538420Smckusick 16638420Smckusick mp = *mrep; 16738420Smckusick mbufcp = *dpos; 16838420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 16938420Smckusick rem = nfsm_rndup(siz)-siz; 17038420Smckusick while (siz > 0) { 17138420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 17238420Smckusick return(EFBIG); 17338420Smckusick left = uiop->uio_iov->iov_len; 17438420Smckusick uiocp = uiop->uio_iov->iov_base; 17538420Smckusick if (left > siz) 17638420Smckusick left = siz; 17738420Smckusick uiosiz = left; 17838420Smckusick while (left > 0) { 17938420Smckusick while (len == 0) { 18038420Smckusick mp = mp->m_next; 18138420Smckusick if (mp == NULL) 18238420Smckusick return (EBADRPC); 18338420Smckusick mbufcp = mtod(mp, caddr_t); 18438420Smckusick len = mp->m_len; 18538420Smckusick } 18638420Smckusick xfer = (left > len) ? len : left; 18738420Smckusick #ifdef notdef 18838420Smckusick /* Not Yet.. */ 18938420Smckusick if (uiop->uio_iov->iov_op != NULL) 19038420Smckusick (*(uiop->uio_iov->iov_op)) 19138420Smckusick (mbufcp, uiocp, xfer); 19238420Smckusick else 19338420Smckusick #endif 19438420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 19538420Smckusick bcopy(mbufcp, uiocp, xfer); 19638420Smckusick else 19738420Smckusick copyout(mbufcp, uiocp, xfer); 19838420Smckusick left -= xfer; 19938420Smckusick len -= xfer; 20038420Smckusick mbufcp += xfer; 20138420Smckusick uiocp += xfer; 20238420Smckusick uiop->uio_resid -= xfer; 20338420Smckusick } 20438420Smckusick if (uiop->uio_iov->iov_len <= siz) { 20538420Smckusick uiop->uio_iovcnt--; 20638420Smckusick uiop->uio_iov++; 20738420Smckusick } else { 20838420Smckusick uiop->uio_iov->iov_base += uiosiz; 20938420Smckusick uiop->uio_iov->iov_len -= uiosiz; 21038420Smckusick } 21138420Smckusick siz -= uiosiz; 21238420Smckusick } 21338420Smckusick if (rem > 0) 21438420Smckusick mbufcp += rem; 21538420Smckusick *dpos = mbufcp; 21638420Smckusick *mrep = mp; 21738420Smckusick return(0); 21838420Smckusick } 21938420Smckusick 22038420Smckusick /* 22138420Smckusick * copies a uio scatter/gather list to an mbuf chain... 22238420Smckusick */ 22338420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 22438420Smckusick register struct uio *uiop; 22538420Smckusick struct mbuf **mq; 22638420Smckusick int siz; 22738420Smckusick caddr_t *bpos; 22838420Smckusick { 22938420Smckusick register struct mbuf *mp; 23038420Smckusick struct mbuf *mp2; 23138420Smckusick long xfer, left, uiosiz, off; 23238420Smckusick int clflg; 23338420Smckusick int rem, len; 23438420Smckusick char *cp, *uiocp; 23538420Smckusick 23638420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 23738420Smckusick clflg = 1; 23838420Smckusick else 23938420Smckusick clflg = 0; 24038420Smckusick rem = nfsm_rndup(siz)-siz; 24138420Smckusick mp2 = *mq; 24238420Smckusick while (siz > 0) { 24338420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 24438420Smckusick return(EINVAL); 24538420Smckusick left = uiop->uio_iov->iov_len; 24638420Smckusick uiocp = uiop->uio_iov->iov_base; 24738420Smckusick if (left > siz) 24838420Smckusick left = siz; 24938420Smckusick uiosiz = left; 25038420Smckusick while (left > 0) { 25138420Smckusick MGET(mp, M_WAIT, MT_DATA); 25238420Smckusick if (clflg) 25338420Smckusick NFSMCLGET(mp, M_WAIT); 25438420Smckusick mp->m_len = NFSMSIZ(mp); 25538420Smckusick mp2->m_next = mp; 25638420Smckusick mp2 = mp; 25738420Smckusick xfer = (left > mp->m_len) ? mp->m_len : left; 25838420Smckusick #ifdef notdef 25938420Smckusick /* Not Yet.. */ 26038420Smckusick if (uiop->uio_iov->iov_op != NULL) 26138420Smckusick (*(uiop->uio_iov->iov_op)) 26238420Smckusick (uiocp, mtod(mp, caddr_t), xfer); 26338420Smckusick else 26438420Smckusick #endif 26538420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 26638420Smckusick bcopy(uiocp, mtod(mp, caddr_t), xfer); 26738420Smckusick else 26838420Smckusick copyin(uiocp, mtod(mp, caddr_t), xfer); 26938420Smckusick len = mp->m_len; 27038420Smckusick mp->m_len = xfer; 27138420Smckusick left -= xfer; 27238420Smckusick uiocp += xfer; 27338420Smckusick uiop->uio_resid -= xfer; 27438420Smckusick } 27538420Smckusick if (uiop->uio_iov->iov_len <= siz) { 27638420Smckusick uiop->uio_iovcnt--; 27738420Smckusick uiop->uio_iov++; 27838420Smckusick } else { 27938420Smckusick uiop->uio_iov->iov_base += uiosiz; 28038420Smckusick uiop->uio_iov->iov_len -= uiosiz; 28138420Smckusick } 28238420Smckusick siz -= uiosiz; 28338420Smckusick } 28438420Smckusick if (rem > 0) { 28538420Smckusick if (rem > (len-mp->m_len)) { 28638420Smckusick MGET(mp, M_WAIT, MT_DATA); 28738420Smckusick mp->m_len = 0; 28838420Smckusick mp2->m_next = mp; 28938420Smckusick } 29038420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 29138420Smckusick for (left = 0; left < rem; left++) 29238420Smckusick *cp++ = '\0'; 29338420Smckusick mp->m_len += rem; 29438420Smckusick *bpos = cp; 29538420Smckusick } else 29638420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 29738420Smckusick *mq = mp; 29838420Smckusick return(0); 29938420Smckusick } 30038420Smckusick 30138420Smckusick /* 30238420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 30338420Smckusick * pointed to by returned val. 30438420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 30538420Smckusick * This is used by the macros nfsm_disect and nfsm_disecton for tough 30638420Smckusick * cases. (The macros use the vars. dpos and dpos2) 30738420Smckusick */ 30838420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 30938420Smckusick struct mbuf **mdp; 31038420Smckusick caddr_t *dposp; 31138420Smckusick int siz; 31238420Smckusick int left; 31338420Smckusick int updateflg; 31438420Smckusick caddr_t *cp2; 31538420Smckusick { 31638420Smckusick register struct mbuf *mp, *mp2; 31738420Smckusick register int siz2, xfer; 31838420Smckusick register caddr_t p; 31938420Smckusick caddr_t p2; 32038420Smckusick 32138420Smckusick mp = *mdp; 32238420Smckusick while (left == 0) { 32338420Smckusick *mdp = mp = mp->m_next; 32438420Smckusick if (mp == NULL) 32538420Smckusick return(EBADRPC); 32638420Smckusick left = mp->m_len; 32738420Smckusick *dposp = mtod(mp, caddr_t); 32838420Smckusick } 32938420Smckusick if (left >= siz) { 33038420Smckusick *cp2 = *dposp; 33138420Smckusick *dposp += siz; 33238420Smckusick return(0); 33338420Smckusick } else if (mp->m_next == NULL) { 33438420Smckusick return(EBADRPC); 33538420Smckusick } else if (siz > MCLBYTES) { 33638420Smckusick panic("nfs S too big"); 33738420Smckusick } else { 33838420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 33938420Smckusick if (updateflg) { 34038420Smckusick NFSMINOFF(mp); 34138420Smckusick } else { 34238420Smckusick MGET(mp2, M_WAIT, MT_DATA); 34338420Smckusick mp2->m_next = mp->m_next; 34438420Smckusick mp->m_next = mp2; 34538420Smckusick mp->m_len -= left; 34638420Smckusick mp = mp2; 34738420Smckusick } 34838420Smckusick /* Alloc cluster iff we need it */ 34938420Smckusick if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) { 35038420Smckusick NFSMCLGET(mp, M_WAIT); 35138420Smckusick if (!M_HASCL(mp)) 35238420Smckusick return(ENOBUFS); 35338420Smckusick } 35438420Smckusick *cp2 = p = mtod(mp, caddr_t); 35538420Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 35638420Smckusick siz2 = siz-left; 35738420Smckusick p += left; 35838420Smckusick mp2 = mp->m_next; 35938420Smckusick /* Loop arround copying up the siz2 bytes */ 36038420Smckusick while (siz2 > 0) { 36138420Smckusick if (mp2 == NULL) 36238420Smckusick return (EBADRPC); 36338420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 36438420Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 36538420Smckusick NFSMADV(mp2, xfer); 36638420Smckusick mp2->m_len -= xfer; 36738420Smckusick siz2 -= xfer; 36838420Smckusick if (siz2 > 0) 36938420Smckusick mp2 = mp2->m_next; 37038420Smckusick } 37138420Smckusick mp->m_len = siz; 37238420Smckusick *mdp = mp2; 37338420Smckusick *dposp = mtod(mp2, caddr_t); 37438420Smckusick return (0); 37538420Smckusick } 37638420Smckusick } 37738420Smckusick 37838420Smckusick /* 37938420Smckusick * Advance the position in the mbuf chain with/without freeing mbufs 38038420Smckusick */ 38138420Smckusick nfs_adv(mdp, dposp, offs, left) 38238420Smckusick struct mbuf **mdp; 38338420Smckusick caddr_t *dposp; 38438420Smckusick int offs; 38538420Smckusick int left; 38638420Smckusick { 38738420Smckusick register struct mbuf *m; 38838420Smckusick register int s; 38938420Smckusick 39038420Smckusick m = *mdp; 39138420Smckusick s = left; 39238420Smckusick while (s < offs) { 39338420Smckusick offs -= s; 39438420Smckusick m = m->m_next; 39538420Smckusick if (m == NULL) 39638420Smckusick return(EBADRPC); 39738420Smckusick s = m->m_len; 39838420Smckusick } 39938420Smckusick *mdp = m; 40038420Smckusick *dposp = mtod(m, caddr_t)+offs; 40138420Smckusick return(0); 40238420Smckusick } 40338420Smckusick 40438420Smckusick /* 40538420Smckusick * Copy a string into mbufs for the hard cases... 40638420Smckusick */ 40738420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 40838420Smckusick struct mbuf **mb; 40938420Smckusick char **bpos; 41038420Smckusick char *cp; 41138420Smckusick long siz; 41238420Smckusick { 41338420Smckusick register struct mbuf *m1, *m2; 41438420Smckusick long left, xfer, len, tlen; 41538420Smckusick u_long *p; 41638420Smckusick int putsize; 41738420Smckusick 41838420Smckusick putsize = 1; 41938420Smckusick m2 = *mb; 42038420Smckusick left = NFSMSIZ(m2)-m2->m_len; 42138420Smckusick if (left > 0) { 42238420Smckusick p = ((u_long *)(*bpos)); 42338420Smckusick *p++ = txdr_unsigned(siz); 42438420Smckusick putsize = 0; 42538420Smckusick left -= NFSX_UNSIGNED; 42638420Smckusick m2->m_len += NFSX_UNSIGNED; 42738420Smckusick if (left > 0) { 42838420Smckusick bcopy(cp, (caddr_t) p, left); 42938420Smckusick siz -= left; 43038420Smckusick cp += left; 43138420Smckusick m2->m_len += left; 43238420Smckusick left = 0; 43338420Smckusick } 43438420Smckusick } 43538420Smckusick /* Loop arround adding mbufs */ 43638420Smckusick while (siz > 0) { 43738420Smckusick MGET(m1, M_WAIT, MT_DATA); 43838420Smckusick if (siz > MLEN) 43938420Smckusick NFSMCLGET(m1, M_WAIT); 44038420Smckusick m1->m_len = NFSMSIZ(m1); 44138420Smckusick m2->m_next = m1; 44238420Smckusick m2 = m1; 44338420Smckusick p = mtod(m1, u_long *); 44438420Smckusick tlen = 0; 44538420Smckusick if (putsize) { 44638420Smckusick *p++ = txdr_unsigned(siz); 44738420Smckusick m1->m_len -= NFSX_UNSIGNED; 44838420Smckusick tlen = NFSX_UNSIGNED; 44938420Smckusick putsize = 0; 45038420Smckusick } 45138420Smckusick if (siz < m1->m_len) { 45238420Smckusick len = nfsm_rndup(siz); 45338420Smckusick xfer = siz; 45438420Smckusick if (xfer < len) 45538420Smckusick *(p+(xfer>>2)) = 0; 45638420Smckusick } else { 45738420Smckusick xfer = len = m1->m_len; 45838420Smckusick } 45938420Smckusick bcopy(cp, (caddr_t) p, xfer); 46038420Smckusick m1->m_len = len+tlen; 46138420Smckusick siz -= xfer; 46238420Smckusick cp += xfer; 46338420Smckusick } 46438420Smckusick *mb = m1; 46538420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 46638420Smckusick return(0); 46738420Smckusick } 46838420Smckusick 46938420Smckusick /* 47038420Smckusick * Called once to initialize data structures... 47138420Smckusick */ 47238420Smckusick nfsinit() 47338420Smckusick { 47438420Smckusick register int i; 47538420Smckusick 47638420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 47738420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 47838420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 47938420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 48038420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 48138420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 48238420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 48338420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 48438420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 48538420Smckusick nfs_true = txdr_unsigned(TRUE); 48638420Smckusick nfs_false = txdr_unsigned(FALSE); 48738420Smckusick /* Loop thru nfs procids */ 48838420Smckusick for (i = 0; i < NFS_NPROCS; i++) 48938420Smckusick nfs_procids[i] = txdr_unsigned(i); 49038420Smckusick v_type[0] = VNON; 49138420Smckusick v_type[1] = VREG; 49238420Smckusick v_type[2] = VDIR; 49338420Smckusick v_type[3] = VBLK; 49438420Smckusick v_type[4] = VCHR; 49538420Smckusick v_type[5] = VLNK; 49638420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 49738420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 49838420Smckusick /* And start timer */ 49938420Smckusick nfs_timer(); 50038420Smckusick } 50138420Smckusick 50238420Smckusick /* 50338420Smckusick * Fill in the rest of the rpc_unixauth and return it 50438420Smckusick */ 50538420Smckusick static char *nfs_unixauth(cr) 50638420Smckusick register struct ucred *cr; 50738420Smckusick { 50838420Smckusick register u_long *p; 50938420Smckusick register int i; 51038420Smckusick int ngr; 51138420Smckusick 51238420Smckusick /* Maybe someday there should be a cache of AUTH_SHORT's */ 51338420Smckusick if ((p = rpc_uidp) == NULL) { 51438420Smckusick i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); 51538420Smckusick MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 51638420Smckusick bzero((caddr_t)p, i); 51738420Smckusick rpc_unixauth = (caddr_t)p; 51838420Smckusick *p++ = txdr_unsigned(RPCAUTH_UNIX); 51938420Smckusick p++; /* Fill in size later */ 52038420Smckusick *p++ = hostid; 52138420Smckusick *p++ = txdr_unsigned(hostnamelen); 52238420Smckusick i = nfsm_rndup(hostnamelen); 52338420Smckusick bcopy(hostname, (caddr_t)p, hostnamelen); 52438420Smckusick p += (i>>2); 52538420Smckusick rpc_uidp = p; 52638420Smckusick } 52738420Smckusick *p++ = txdr_unsigned(cr->cr_uid); 52838420Smckusick *p++ = txdr_unsigned(cr->cr_groups[0]); 52938420Smckusick ngr = (cr->cr_ngroups > 10) ? 10 : cr->cr_ngroups; 53038420Smckusick *p++ = txdr_unsigned(ngr); 53138420Smckusick for (i = 0; i < ngr; i++) 53238420Smckusick *p++ = txdr_unsigned(cr->cr_groups[i]); 53338420Smckusick /* And add the AUTH_NULL */ 53438420Smckusick *p++ = 0; 53538420Smckusick *p = 0; 53638420Smckusick i = (((caddr_t)p)-rpc_unixauth)-12; 53738420Smckusick p = (u_long *)(rpc_unixauth+4); 53838420Smckusick *p = txdr_unsigned(i); 53938420Smckusick return(rpc_unixauth); 54038420Smckusick } 54138420Smckusick 54238420Smckusick /* 54338420Smckusick * Attribute cache routines. 54438420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 54538420Smckusick * that are on the mbuf list 54638420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 54738420Smckusick * error otherwise 54838420Smckusick */ 54938420Smckusick 55038420Smckusick /* 55138420Smckusick * Load the attribute cache (that lives in the nfsnode table) with 55238420Smckusick * the values on the mbuf list and 55338420Smckusick * Iff vap not NULL 55438420Smckusick * copy the attributes to *vaper 55538420Smckusick */ 55638420Smckusick nfs_loadattrcache(vp, mdp, dposp, vaper) 55738420Smckusick register struct vnode *vp; 55838420Smckusick struct mbuf **mdp; 55938420Smckusick caddr_t *dposp; 56038420Smckusick struct vattr *vaper; 56138420Smckusick { 56238420Smckusick register struct vattr *vap; 56338420Smckusick nfsm_vars; 56438420Smckusick struct nfsnode *np; 56538420Smckusick 56638420Smckusick md = *mdp; 56738420Smckusick dpos = *dposp; 56838420Smckusick t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 56938420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 57038420Smckusick return (error); 57138420Smckusick p = (u_long *)cp2; 57238420Smckusick np = VTONFS(vp); 57338420Smckusick vap = &np->n_vattr; 57438420Smckusick vap->va_type = nfstov_type(*p++); 57538420Smckusick vap->va_mode = nfstov_mode(*p++); 57638420Smckusick vap->va_nlink = fxdr_unsigned(u_short, *p++); 57738420Smckusick vap->va_uid = fxdr_unsigned(uid_t, *p++); 57838420Smckusick vap->va_gid = fxdr_unsigned(gid_t, *p++); 57938420Smckusick vap->va_size = fxdr_unsigned(u_long, *p++); 58038420Smckusick vap->va_size1 = 0; /* OR -1 ?? */ 58138420Smckusick vap->va_blocksize = fxdr_unsigned(long, *p++); 58238420Smckusick vap->va_rdev = fxdr_unsigned(dev_t, *p++); 58338420Smckusick vap->va_bytes = fxdr_unsigned(long, *p++); 58438420Smckusick vap->va_bytes1 = -1; 58538420Smckusick vap->va_fsid = fxdr_unsigned(long, *p++); 58638420Smckusick vap->va_fileid = fxdr_unsigned(long, *p++); 58738420Smckusick fxdr_time(p, &(vap->va_atime)); 58838420Smckusick p += 2; 58938420Smckusick fxdr_time(p, &(vap->va_mtime)); 59038420Smckusick p += 2; 59138420Smckusick fxdr_time(p, &(vap->va_ctime)); 59238420Smckusick np->n_attrstamp = time.tv_sec; 59338420Smckusick *dposp = dpos; 59438420Smckusick *mdp = md; 59538420Smckusick if (vaper != NULL) 59638420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 59738420Smckusick return (0); 59838420Smckusick } 59938420Smckusick 60038420Smckusick /* 60138420Smckusick * Check the time stamp 60238420Smckusick * If the cache is valid, copy contents to *vap and return 0 60338420Smckusick * otherwise return an error 60438420Smckusick */ 60538420Smckusick nfs_getattrcache(vp, vap) 60638420Smckusick register struct vnode *vp; 60738420Smckusick struct vattr *vap; 60838420Smckusick { 60938420Smckusick register struct nfsnode *np; 61038420Smckusick 61138420Smckusick np = VTONFS(vp); 61238420Smckusick if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 61338420Smckusick nfsstats.attrcache_hits++; 61438420Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 61538420Smckusick return (0); 61638420Smckusick } else { 61738420Smckusick nfsstats.attrcache_misses++; 61838420Smckusick return (ENOENT); 61938420Smckusick } 62038420Smckusick } 62138420Smckusick 62238420Smckusick #ifndef OPFLAG 62338420Smckusick #define OPFLAG (CREATE | DELETE | LOOKUP) 62438420Smckusick #endif 62538420Smckusick 62638420Smckusick /* 62738420Smckusick * nfs_namei - a liitle like namei(), but for one element only 62838420Smckusick * essentially look up file handle, fill in ndp and call VOP_LOOKUP() 62938420Smckusick */ 63038420Smckusick nfs_namei(ndp, fhp, len, mdp, dposp) 63138420Smckusick register struct nameidata *ndp; 63238420Smckusick fhandle_t *fhp; 63338420Smckusick int len; 63438420Smckusick struct mbuf **mdp; 63538420Smckusick caddr_t *dposp; 63638420Smckusick { 63738420Smckusick register int i, rem; 63838420Smckusick register struct mbuf *md; 63938420Smckusick register char *cp; 64038420Smckusick struct vnode *dp = (struct vnode *)0; 64138420Smckusick struct vnode *tdp; 64238420Smckusick struct mount *mp; 64338420Smckusick int flag; 64438420Smckusick int docache; 64538420Smckusick int wantparent; 64638420Smckusick int lockparent; 64738420Smckusick int rootflg = 0; 64838420Smckusick int error = 0; 64938420Smckusick 65038420Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 65138420Smckusick flag = ndp->ni_nameiop & OPFLAG; 65238420Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT); 65338420Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 65438420Smckusick docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 65538420Smckusick if (flag == DELETE || wantparent) 65638420Smckusick docache = 0; 65738420Smckusick 65838420Smckusick /* Fill in the nameidata and call lookup */ 65938420Smckusick cp = *dposp; 66038420Smckusick md = *mdp; 66138420Smckusick rem = mtod(md, caddr_t)+md->m_len-cp; 66238420Smckusick ndp->ni_hash = 0; 66338420Smckusick for (i = 0; i < len;) { 66438420Smckusick if (rem == 0) { 66538420Smckusick md = md->m_next; 66638420Smckusick if (md == NULL) 66738420Smckusick return (EBADRPC); 66838420Smckusick cp = mtod(md, caddr_t); 66938420Smckusick rem = md->m_len; 67038420Smckusick } 67138420Smckusick if (*cp == '\0' || *cp == '/') 67238420Smckusick return (EINVAL); 67338420Smckusick if (*cp & 0200) 67438420Smckusick if ((*cp&0377) == ('/'|0200) || flag != DELETE) 67538420Smckusick return (EINVAL); 67638420Smckusick ndp->ni_dent.d_name[i++] = *cp; 67738420Smckusick ndp->ni_hash += (unsigned char)*cp * i; 67838420Smckusick cp++; 67938420Smckusick rem--; 68038420Smckusick } 68138420Smckusick *mdp = md; 68238420Smckusick len = nfsm_rndup(len)-len; 68338420Smckusick if (len > 0) 68438420Smckusick *dposp = cp+len; 68538420Smckusick else 68638420Smckusick *dposp = cp; 68738420Smckusick ndp->ni_namelen = i; 68838420Smckusick ndp->ni_dent.d_namlen = i; 68938420Smckusick ndp->ni_dent.d_name[i] = '\0'; 69038420Smckusick ndp->ni_pathlen = 0; 69138420Smckusick ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 69238420Smckusick ndp->ni_next = &ndp->ni_dent.d_name[i]; 69338420Smckusick ndp->ni_loopcnt = 0; /* Not actually used for now */ 69438420Smckusick ndp->ni_endoff = 0; 69538420Smckusick if (docache) 69638420Smckusick ndp->ni_makeentry = 1; 69738420Smckusick else 69838420Smckusick ndp->ni_makeentry = 0; 69938420Smckusick ndp->ni_isdotdot = (i == 2 && 70038420Smckusick ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.'); 70138420Smckusick 70238420Smckusick /* 70338420Smckusick * Must remember if this is root so that cr_uid can be set to 70438420Smckusick * mp->m_exroot at mount points 70538420Smckusick * Then call nfsrv_fhtovp() to get the locked directory vnode 70638420Smckusick */ 70738420Smckusick if (ndp->ni_cred->cr_uid == 0) 70838420Smckusick rootflg++; 70938420Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred)) 71038420Smckusick return (error); 71138420Smckusick 71238420Smckusick /* 71338420Smckusick * Handle "..": two special cases. 71438420Smckusick * 1. If at root directory (e.g. after chroot) 71538420Smckusick * then ignore it so can't get out. 71638420Smckusick * 2. If this vnode is the root of a mounted 71738420Smckusick * file system, then replace it with the 71838420Smckusick * vnode which was mounted on so we take the 71938420Smckusick * .. in the other file system. 72038420Smckusick */ 72138420Smckusick if (ndp->ni_isdotdot) { 72238420Smckusick for (;;) { 72338420Smckusick if (dp == rootdir) { 72438420Smckusick ndp->ni_dvp = dp; 72538420Smckusick dp->v_count++; 72638420Smckusick goto nextname; 72738420Smckusick } 72838420Smckusick if ((dp->v_flag & VROOT) == 0) 72938420Smckusick break; 73038420Smckusick tdp = dp; 73138420Smckusick dp = dp->v_mount->m_vnodecovered; 73238420Smckusick vput(tdp); 73338420Smckusick if ((dp->v_mount->m_flag & M_EXPORTED) == 0) 73438420Smckusick return (EACCES); 73538420Smckusick VOP_LOCK(dp); 73638420Smckusick dp->v_count++; 73738420Smckusick if (rootflg) 73838420Smckusick ndp->ni_cred->cr_uid = dp->v_mount->m_exroot; 73938420Smckusick } 74038420Smckusick } 74138420Smckusick 74238420Smckusick /* 74338420Smckusick * We now have a segment name to search for, and a directory to search. 74438420Smckusick */ 74538420Smckusick if (error = VOP_LOOKUP(dp, ndp)) { 74638420Smckusick if (ndp->ni_vp != NULL) 74738420Smckusick panic("leaf should be empty"); 74838420Smckusick /* 74938420Smckusick * If creating and at end of pathname, then can consider 75038420Smckusick * allowing file to be created. 75138420Smckusick */ 75238420Smckusick if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) 75338420Smckusick error = EROFS; 75438420Smckusick if (flag == LOOKUP || flag == DELETE || error != ENOENT) 75538420Smckusick goto bad; 75638420Smckusick /* 75738420Smckusick * We return with ni_vp NULL to indicate that the entry 75838420Smckusick * doesn't currently exist, leaving a pointer to the 75938420Smckusick * (possibly locked) directory inode in ndp->ni_dvp. 76038420Smckusick */ 76138420Smckusick return (0); /* should this be ENOENT? */ 76238420Smckusick } 76338420Smckusick 76438420Smckusick /* 76538420Smckusick * Check for symbolic link 76638420Smckusick */ 76738420Smckusick dp = ndp->ni_vp; 76838420Smckusick #ifdef notdef 76938420Smckusick if ((dp->v_type == VLNK) && 77038420Smckusick (ndp->ni_nameiop & FOLLOW)) { 77138420Smckusick struct iovec aiov; 77238420Smckusick struct uio auio; 77338420Smckusick int linklen; 77438420Smckusick 77538420Smckusick if (++ndp->ni_loopcnt > MAXSYMLINKS) { 77638420Smckusick error = ELOOP; 77738420Smckusick goto bad2; 77838420Smckusick } 77938420Smckusick MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78038420Smckusick aiov.iov_base = cp; 78138420Smckusick aiov.iov_len = MAXPATHLEN; 78238420Smckusick auio.uio_iov = &aiov; 78338420Smckusick auio.uio_iovcnt = 1; 78438420Smckusick auio.uio_offset = 0; 78538420Smckusick auio.uio_rw = UIO_READ; 78638420Smckusick auio.uio_segflg = UIO_SYSSPACE; 78738420Smckusick auio.uio_resid = MAXPATHLEN; 78838420Smckusick if (error = VOP_READLINK(dp, &auio, ndp->ni_cred)) { 78938420Smckusick free(cp, M_NAMEI); 79038420Smckusick goto bad2; 79138420Smckusick } 79238420Smckusick linklen = MAXPATHLEN - auio.uio_resid; 79338420Smckusick if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 79438420Smckusick free(cp, M_NAMEI); 79538420Smckusick error = ENAMETOOLONG; 79638420Smckusick goto bad2; 79738420Smckusick } 79838420Smckusick bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 79938420Smckusick ndp->ni_pnbuf = cp; 80038420Smckusick } else 80138420Smckusick ndp->ni_pnbuf[linklen] = '\0'; 80238420Smckusick ndp->ni_ptr = cp; 80338420Smckusick ndp->ni_pathlen += linklen; 80438420Smckusick vput(dp); 80538420Smckusick dp = ndp->ni_dvp; 80638420Smckusick goto start; 80738420Smckusick } 80838420Smckusick #endif 80938420Smckusick 81038420Smckusick /* 81138420Smckusick * Check to see if the vnode has been mounted on; 81238420Smckusick * if so find the root of the mounted file system. 81338420Smckusick * Ignore NFS mount points 81438420Smckusick */ 81538420Smckusick mntloop: 81638420Smckusick while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 81738420Smckusick mp->m_fsid.val[1] != MOUNT_NFS) { 81838420Smckusick while(mp->m_flag & M_MLOCK) { 81938420Smckusick mp->m_flag |= M_MWAIT; 82038420Smckusick sleep((caddr_t)mp, PVFS); 82138420Smckusick goto mntloop; 82238420Smckusick } 82338420Smckusick error = VFS_ROOT(mp, &tdp); 82438420Smckusick if (error || (mp->m_flag & M_EXPORTED) == 0) 82538420Smckusick goto bad2; 82638420Smckusick vput(dp); 82738420Smckusick ndp->ni_vp = dp = tdp; 82838420Smckusick if (rootflg) 82938420Smckusick ndp->ni_cred->cr_uid = mp->m_exroot; 83038420Smckusick } 83138420Smckusick 83238420Smckusick nextname: 83338420Smckusick /* 834*38421Smckusick * Check for read-only file systems. 83538420Smckusick */ 836*38421Smckusick if (flag == DELETE || flag == RENAME) { 837*38421Smckusick /* 838*38421Smckusick * Disallow directory write attempts on read-only 839*38421Smckusick * file systems. 840*38421Smckusick */ 841*38421Smckusick if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) || 842*38421Smckusick (wantparent && (ndp->ni_dvp->v_mount->m_flag & M_RDONLY))) { 843*38421Smckusick error = EROFS; 844*38421Smckusick goto bad2; 845*38421Smckusick } 846*38421Smckusick } 84738420Smckusick 84838420Smckusick /* 84938420Smckusick * Kludge city... This is hokey, but since ufs_rename() calls 85038420Smckusick * namei() and namei() expects ni_cdir to be set, what can I 85138420Smckusick * do. Fortunately rename() holds onto the parent so I don't 85238420Smckusick * have to increment the v_count. 85338420Smckusick */ 85438420Smckusick if (!wantparent) 85538420Smckusick vrele(ndp->ni_dvp); 85638420Smckusick else 85738420Smckusick ndp->ni_cdir = ndp->ni_dvp; 85838420Smckusick 85938420Smckusick if ((ndp->ni_nameiop & LOCKLEAF) == 0) 86038420Smckusick VOP_UNLOCK(dp); 86138420Smckusick return (0); 86238420Smckusick 86338420Smckusick bad2: 86438420Smckusick if (lockparent) 86538420Smckusick VOP_UNLOCK(ndp->ni_dvp); 86638420Smckusick vrele(ndp->ni_dvp); 86738420Smckusick bad: 86838420Smckusick vput(dp); 86938420Smckusick ndp->ni_vp = NULL; 87038420Smckusick return (error); 87138420Smckusick } 87238420Smckusick 87338420Smckusick /* 87438420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 87538420Smckusick * boundary and only trims off the back end 87638420Smckusick */ 87738420Smckusick nfsm_adj(mp, len, nul) 87838420Smckusick struct mbuf *mp; 87938420Smckusick register int len; 88038420Smckusick int nul; 88138420Smckusick { 88238420Smckusick register struct mbuf *m; 88338420Smckusick register int count, i; 88438420Smckusick register char *cp; 88538420Smckusick 88638420Smckusick /* 88738420Smckusick * Trim from tail. Scan the mbuf chain, 88838420Smckusick * calculating its length and finding the last mbuf. 88938420Smckusick * If the adjustment only affects this mbuf, then just 89038420Smckusick * adjust and return. Otherwise, rescan and truncate 89138420Smckusick * after the remaining size. 89238420Smckusick */ 89338420Smckusick count = 0; 89438420Smckusick m = mp; 89538420Smckusick for (;;) { 89638420Smckusick count += m->m_len; 89738420Smckusick if (m->m_next == (struct mbuf *)0) 89838420Smckusick break; 89938420Smckusick m = m->m_next; 90038420Smckusick } 90138420Smckusick if (m->m_len >= len) { 90238420Smckusick m->m_len -= len; 90338420Smckusick if (nul > 0) { 90438420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 90538420Smckusick for (i = 0; i < nul; i++) 90638420Smckusick *cp++ = '\0'; 90738420Smckusick } 90838420Smckusick return; 90938420Smckusick } 91038420Smckusick count -= len; 91138420Smckusick if (count < 0) 91238420Smckusick count = 0; 91338420Smckusick /* 91438420Smckusick * Correct length for chain is "count". 91538420Smckusick * Find the mbuf with last data, adjust its length, 91638420Smckusick * and toss data from remaining mbufs on chain. 91738420Smckusick */ 91838420Smckusick for (m = mp; m; m = m->m_next) { 91938420Smckusick if (m->m_len >= count) { 92038420Smckusick m->m_len = count; 92138420Smckusick if (nul > 0) { 92238420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 92338420Smckusick for (i = 0; i < nul; i++) 92438420Smckusick *cp++ = '\0'; 92538420Smckusick } 92638420Smckusick break; 92738420Smckusick } 92838420Smckusick count -= m->m_len; 92938420Smckusick } 93038420Smckusick while (m = m->m_next) 93138420Smckusick m->m_len = 0; 93238420Smckusick } 93338420Smckusick 93438420Smckusick /* 93538420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 93638420Smckusick * - look up fsid in mount list (if not found ret error) 93738420Smckusick * - check that it is exported 93838420Smckusick * - get vp by calling VFS_FHTOVP() macro 93938420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 94038420Smckusick * - if cred->cr_uid == 0 set it to m_exroot 94138420Smckusick */ 94238420Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred) 94338420Smckusick fhandle_t *fhp; 94438420Smckusick int lockflag; 94538420Smckusick struct vnode **vpp; 94638420Smckusick struct ucred *cred; 94738420Smckusick { 94838420Smckusick register struct mount *mp; 94938420Smckusick int error; 95038420Smckusick 95138420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 95238420Smckusick return (ESTALE); 95338420Smckusick if ((mp->m_flag & M_EXPORTED) == 0) 95438420Smckusick return (EACCES); 95538420Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 95638420Smckusick return (ESTALE); 95738420Smckusick if (cred->cr_uid == 0) 95838420Smckusick cred->cr_uid = mp->m_exroot; 95938420Smckusick if (!lockflag) 96038420Smckusick VOP_UNLOCK(*vpp); 96138420Smckusick return (0); 96238420Smckusick } 96338420Smckusick 964