nfs_srvsubs.c revision 1549
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley by
61541Srgrimes * Rick Macklem at The University of Guelph.
71541Srgrimes *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 3. All advertising materials mentioning features or use of this software
171541Srgrimes *    must display the following acknowledgement:
181541Srgrimes *	This product includes software developed by the University of
191541Srgrimes *	California, Berkeley and its contributors.
201541Srgrimes * 4. Neither the name of the University nor the names of its contributors
211541Srgrimes *    may be used to endorse or promote products derived from this software
221541Srgrimes *    without specific prior written permission.
231541Srgrimes *
241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341541Srgrimes * SUCH DAMAGE.
351541Srgrimes *
361541Srgrimes *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
371541Srgrimes */
381541Srgrimes
391541Srgrimes/*
401541Srgrimes * These functions support the macros and help fiddle mbuf chains for
411541Srgrimes * the nfs op functions. They do things like create the rpc header and
421541Srgrimes * copy data between mbuf chains and uio lists.
431541Srgrimes */
441541Srgrimes#include <sys/param.h>
451541Srgrimes#include <sys/proc.h>
461541Srgrimes#include <sys/systm.h>
471541Srgrimes#include <sys/kernel.h>
481541Srgrimes#include <sys/mount.h>
491541Srgrimes#include <sys/vnode.h>
501541Srgrimes#include <sys/namei.h>
511541Srgrimes#include <sys/mbuf.h>
521541Srgrimes#include <sys/socket.h>
531541Srgrimes#include <sys/stat.h>
541541Srgrimes
551541Srgrimes#include <nfs/rpcv2.h>
561541Srgrimes#include <nfs/nfsv2.h>
571541Srgrimes#include <nfs/nfsnode.h>
581541Srgrimes#include <nfs/nfs.h>
591541Srgrimes#include <nfs/xdr_subs.h>
601541Srgrimes#include <nfs/nfsm_subs.h>
611541Srgrimes#include <nfs/nfsmount.h>
621541Srgrimes#include <nfs/nqnfs.h>
631541Srgrimes#include <nfs/nfsrtt.h>
641541Srgrimes
651541Srgrimes#include <miscfs/specfs/specdev.h>
661541Srgrimes
671541Srgrimes#include <netinet/in.h>
681541Srgrimes#ifdef ISO
691541Srgrimes#include <netiso/iso.h>
701541Srgrimes#endif
711541Srgrimes
721541Srgrimes#define TRUE	1
731541Srgrimes#define	FALSE	0
741541Srgrimes
751541Srgrimes/*
761541Srgrimes * Data items converted to xdr at startup, since they are constant
771541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
781541Srgrimes */
791541Srgrimesu_long nfs_procids[NFS_NPROCS];
801541Srgrimesu_long nfs_xdrneg1;
811541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
821541Srgrimes	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
831541Srgrimes	rpc_auth_kerb;
841541Srgrimesu_long nfs_vers, nfs_prog, nfs_true, nfs_false;
851541Srgrimes
861541Srgrimes/* And other global data */
871541Srgrimesstatic u_long nfs_xid = 0;
881541Srgrimesenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
891541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
901541Srgrimesextern struct nfsreq nfsreqh;
911541Srgrimesextern int nqnfs_piggy[NFS_NPROCS];
921541Srgrimesextern struct nfsrtt nfsrtt;
931541Srgrimesextern time_t nqnfsstarttime;
941541Srgrimesextern u_long nqnfs_prog, nqnfs_vers;
951541Srgrimesextern int nqsrv_clockskew;
961541Srgrimesextern int nqsrv_writeslack;
971541Srgrimesextern int nqsrv_maxlease;
981541Srgrimes
991541Srgrimes/*
1001541Srgrimes * Create the header for an rpc request packet
1011541Srgrimes * The hsiz is the size of the rest of the nfs request header.
1021541Srgrimes * (just used to decide if a cluster is a good idea)
1031541Srgrimes */
1041541Srgrimesstruct mbuf *
1051541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp)
1061541Srgrimes	struct vnode *vp;
1071541Srgrimes	u_long procid;
1081541Srgrimes	int hsiz;
1091541Srgrimes	caddr_t *bposp;
1101541Srgrimes{
1111541Srgrimes	register struct mbuf *mb;
1121541Srgrimes	register u_long *tl;
1131541Srgrimes	register caddr_t bpos;
1141541Srgrimes	struct mbuf *mb2;
1151541Srgrimes	struct nfsmount *nmp;
1161541Srgrimes	int nqflag;
1171541Srgrimes
1181541Srgrimes	MGET(mb, M_WAIT, MT_DATA);
1191541Srgrimes	if (hsiz >= MINCLSIZE)
1201541Srgrimes		MCLGET(mb, M_WAIT);
1211541Srgrimes	mb->m_len = 0;
1221541Srgrimes	bpos = mtod(mb, caddr_t);
1231541Srgrimes
1241541Srgrimes	/*
1251541Srgrimes	 * For NQNFS, add lease request.
1261541Srgrimes	 */
1271541Srgrimes	if (vp) {
1281541Srgrimes		nmp = VFSTONFS(vp->v_mount);
1291541Srgrimes		if (nmp->nm_flag & NFSMNT_NQNFS) {
1301541Srgrimes			nqflag = NQNFS_NEEDLEASE(vp, procid);
1311541Srgrimes			if (nqflag) {
1321541Srgrimes				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1331541Srgrimes				*tl++ = txdr_unsigned(nqflag);
1341541Srgrimes				*tl = txdr_unsigned(nmp->nm_leaseterm);
1351541Srgrimes			} else {
1361541Srgrimes				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1371541Srgrimes				*tl = 0;
1381541Srgrimes			}
1391541Srgrimes		}
1401541Srgrimes	}
1411541Srgrimes	/* Finally, return values */
1421541Srgrimes	*bposp = bpos;
1431541Srgrimes	return (mb);
1441541Srgrimes}
1451541Srgrimes
1461541Srgrimes/*
1471541Srgrimes * Build the RPC header and fill in the authorization info.
1481541Srgrimes * The authorization string argument is only used when the credentials
1491541Srgrimes * come from outside of the kernel.
1501541Srgrimes * Returns the head of the mbuf list.
1511541Srgrimes */
1521541Srgrimesstruct mbuf *
1531541Srgrimesnfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
1541541Srgrimes	mrest_len, mbp, xidp)
1551541Srgrimes	register struct ucred *cr;
1561541Srgrimes	int nqnfs;
1571541Srgrimes	int procid;
1581541Srgrimes	int auth_type;
1591541Srgrimes	int auth_len;
1601541Srgrimes	char *auth_str;
1611541Srgrimes	struct mbuf *mrest;
1621541Srgrimes	int mrest_len;
1631541Srgrimes	struct mbuf **mbp;
1641541Srgrimes	u_long *xidp;
1651541Srgrimes{
1661541Srgrimes	register struct mbuf *mb;
1671541Srgrimes	register u_long *tl;
1681541Srgrimes	register caddr_t bpos;
1691541Srgrimes	register int i;
1701541Srgrimes	struct mbuf *mreq, *mb2;
1711541Srgrimes	int siz, grpsiz, authsiz;
1721541Srgrimes
1731541Srgrimes	authsiz = nfsm_rndup(auth_len);
1741541Srgrimes	if (auth_type == RPCAUTH_NQNFS)
1751541Srgrimes		authsiz += 2 * NFSX_UNSIGNED;
1761541Srgrimes	MGETHDR(mb, M_WAIT, MT_DATA);
1771541Srgrimes	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
1781541Srgrimes		MCLGET(mb, M_WAIT);
1791541Srgrimes	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
1801541Srgrimes		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
1811541Srgrimes	} else {
1821541Srgrimes		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
1831541Srgrimes	}
1841541Srgrimes	mb->m_len = 0;
1851541Srgrimes	mreq = mb;
1861541Srgrimes	bpos = mtod(mb, caddr_t);
1871541Srgrimes
1881541Srgrimes	/*
1891541Srgrimes	 * First the RPC header.
1901541Srgrimes	 */
1911541Srgrimes	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
1921541Srgrimes	if (++nfs_xid == 0)
1931541Srgrimes		nfs_xid++;
1941541Srgrimes	*tl++ = *xidp = txdr_unsigned(nfs_xid);
1951541Srgrimes	*tl++ = rpc_call;
1961541Srgrimes	*tl++ = rpc_vers;
1971541Srgrimes	if (nqnfs) {
1981541Srgrimes		*tl++ = txdr_unsigned(NQNFS_PROG);
1991541Srgrimes		*tl++ = txdr_unsigned(NQNFS_VER1);
2001541Srgrimes	} else {
2011541Srgrimes		*tl++ = txdr_unsigned(NFS_PROG);
2021541Srgrimes		*tl++ = txdr_unsigned(NFS_VER2);
2031541Srgrimes	}
2041541Srgrimes	*tl++ = txdr_unsigned(procid);
2051541Srgrimes
2061541Srgrimes	/*
2071541Srgrimes	 * And then the authorization cred.
2081541Srgrimes	 */
2091541Srgrimes	*tl++ = txdr_unsigned(auth_type);
2101541Srgrimes	*tl = txdr_unsigned(authsiz);
2111541Srgrimes	switch (auth_type) {
2121541Srgrimes	case RPCAUTH_UNIX:
2131541Srgrimes		nfsm_build(tl, u_long *, auth_len);
2141541Srgrimes		*tl++ = 0;		/* stamp ?? */
2151541Srgrimes		*tl++ = 0;		/* NULL hostname */
2161541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
2171541Srgrimes		*tl++ = txdr_unsigned(cr->cr_groups[0]);
2181541Srgrimes		grpsiz = (auth_len >> 2) - 5;
2191541Srgrimes		*tl++ = txdr_unsigned(grpsiz);
2201541Srgrimes		for (i = 1; i <= grpsiz; i++)
2211541Srgrimes			*tl++ = txdr_unsigned(cr->cr_groups[i]);
2221541Srgrimes		break;
2231541Srgrimes	case RPCAUTH_NQNFS:
2241541Srgrimes		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
2251541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
2261541Srgrimes		*tl = txdr_unsigned(auth_len);
2271541Srgrimes		siz = auth_len;
2281541Srgrimes		while (siz > 0) {
2291541Srgrimes			if (M_TRAILINGSPACE(mb) == 0) {
2301541Srgrimes				MGET(mb2, M_WAIT, MT_DATA);
2311541Srgrimes				if (siz >= MINCLSIZE)
2321541Srgrimes					MCLGET(mb2, M_WAIT);
2331541Srgrimes				mb->m_next = mb2;
2341541Srgrimes				mb = mb2;
2351541Srgrimes				mb->m_len = 0;
2361541Srgrimes				bpos = mtod(mb, caddr_t);
2371541Srgrimes			}
2381541Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
2391541Srgrimes			bcopy(auth_str, bpos, i);
2401541Srgrimes			mb->m_len += i;
2411541Srgrimes			auth_str += i;
2421541Srgrimes			bpos += i;
2431541Srgrimes			siz -= i;
2441541Srgrimes		}
2451541Srgrimes		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
2461541Srgrimes			for (i = 0; i < siz; i++)
2471541Srgrimes				*bpos++ = '\0';
2481541Srgrimes			mb->m_len += siz;
2491541Srgrimes		}
2501541Srgrimes		break;
2511541Srgrimes	};
2521541Srgrimes	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
2531541Srgrimes	*tl++ = txdr_unsigned(RPCAUTH_NULL);
2541541Srgrimes	*tl = 0;
2551541Srgrimes	mb->m_next = mrest;
2561541Srgrimes	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
2571541Srgrimes	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
2581541Srgrimes	*mbp = mb;
2591541Srgrimes	return (mreq);
2601541Srgrimes}
2611541Srgrimes
2621541Srgrimes/*
2631541Srgrimes * copies mbuf chain to the uio scatter/gather list
2641541Srgrimes */
2651549Srgrimesint
2661541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos)
2671541Srgrimes	struct mbuf **mrep;
2681541Srgrimes	register struct uio *uiop;
2691541Srgrimes	int siz;
2701541Srgrimes	caddr_t *dpos;
2711541Srgrimes{
2721541Srgrimes	register char *mbufcp, *uiocp;
2731541Srgrimes	register int xfer, left, len;
2741541Srgrimes	register struct mbuf *mp;
2751541Srgrimes	long uiosiz, rem;
2761541Srgrimes	int error = 0;
2771541Srgrimes
2781541Srgrimes	mp = *mrep;
2791541Srgrimes	mbufcp = *dpos;
2801541Srgrimes	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
2811541Srgrimes	rem = nfsm_rndup(siz)-siz;
2821541Srgrimes	while (siz > 0) {
2831541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
2841541Srgrimes			return (EFBIG);
2851541Srgrimes		left = uiop->uio_iov->iov_len;
2861541Srgrimes		uiocp = uiop->uio_iov->iov_base;
2871541Srgrimes		if (left > siz)
2881541Srgrimes			left = siz;
2891541Srgrimes		uiosiz = left;
2901541Srgrimes		while (left > 0) {
2911541Srgrimes			while (len == 0) {
2921541Srgrimes				mp = mp->m_next;
2931541Srgrimes				if (mp == NULL)
2941541Srgrimes					return (EBADRPC);
2951541Srgrimes				mbufcp = mtod(mp, caddr_t);
2961541Srgrimes				len = mp->m_len;
2971541Srgrimes			}
2981541Srgrimes			xfer = (left > len) ? len : left;
2991541Srgrimes#ifdef notdef
3001541Srgrimes			/* Not Yet.. */
3011541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
3021541Srgrimes				(*(uiop->uio_iov->iov_op))
3031541Srgrimes				(mbufcp, uiocp, xfer);
3041541Srgrimes			else
3051541Srgrimes#endif
3061541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
3071541Srgrimes				bcopy(mbufcp, uiocp, xfer);
3081541Srgrimes			else
3091541Srgrimes				copyout(mbufcp, uiocp, xfer);
3101541Srgrimes			left -= xfer;
3111541Srgrimes			len -= xfer;
3121541Srgrimes			mbufcp += xfer;
3131541Srgrimes			uiocp += xfer;
3141541Srgrimes			uiop->uio_offset += xfer;
3151541Srgrimes			uiop->uio_resid -= xfer;
3161541Srgrimes		}
3171541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
3181541Srgrimes			uiop->uio_iovcnt--;
3191541Srgrimes			uiop->uio_iov++;
3201541Srgrimes		} else {
3211541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
3221541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
3231541Srgrimes		}
3241541Srgrimes		siz -= uiosiz;
3251541Srgrimes	}
3261541Srgrimes	*dpos = mbufcp;
3271541Srgrimes	*mrep = mp;
3281541Srgrimes	if (rem > 0) {
3291541Srgrimes		if (len < rem)
3301541Srgrimes			error = nfs_adv(mrep, dpos, rem, len);
3311541Srgrimes		else
3321541Srgrimes			*dpos += rem;
3331541Srgrimes	}
3341541Srgrimes	return (error);
3351541Srgrimes}
3361541Srgrimes
3371541Srgrimes/*
3381541Srgrimes * copies a uio scatter/gather list to an mbuf chain...
3391541Srgrimes */
3401549Srgrimesint
3411541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos)
3421541Srgrimes	register struct uio *uiop;
3431541Srgrimes	struct mbuf **mq;
3441541Srgrimes	int siz;
3451541Srgrimes	caddr_t *bpos;
3461541Srgrimes{
3471541Srgrimes	register char *uiocp;
3481541Srgrimes	register struct mbuf *mp, *mp2;
3491541Srgrimes	register int xfer, left, mlen;
3501541Srgrimes	int uiosiz, clflg, rem;
3511541Srgrimes	char *cp;
3521541Srgrimes
3531541Srgrimes	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
3541541Srgrimes		clflg = 1;
3551541Srgrimes	else
3561541Srgrimes		clflg = 0;
3571541Srgrimes	rem = nfsm_rndup(siz)-siz;
3581541Srgrimes	mp = mp2 = *mq;
3591541Srgrimes	while (siz > 0) {
3601541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
3611541Srgrimes			return (EINVAL);
3621541Srgrimes		left = uiop->uio_iov->iov_len;
3631541Srgrimes		uiocp = uiop->uio_iov->iov_base;
3641541Srgrimes		if (left > siz)
3651541Srgrimes			left = siz;
3661541Srgrimes		uiosiz = left;
3671541Srgrimes		while (left > 0) {
3681541Srgrimes			mlen = M_TRAILINGSPACE(mp);
3691541Srgrimes			if (mlen == 0) {
3701541Srgrimes				MGET(mp, M_WAIT, MT_DATA);
3711541Srgrimes				if (clflg)
3721541Srgrimes					MCLGET(mp, M_WAIT);
3731541Srgrimes				mp->m_len = 0;
3741541Srgrimes				mp2->m_next = mp;
3751541Srgrimes				mp2 = mp;
3761541Srgrimes				mlen = M_TRAILINGSPACE(mp);
3771541Srgrimes			}
3781541Srgrimes			xfer = (left > mlen) ? mlen : left;
3791541Srgrimes#ifdef notdef
3801541Srgrimes			/* Not Yet.. */
3811541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
3821541Srgrimes				(*(uiop->uio_iov->iov_op))
3831541Srgrimes				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
3841541Srgrimes			else
3851541Srgrimes#endif
3861541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
3871541Srgrimes				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
3881541Srgrimes			else
3891541Srgrimes				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
3901541Srgrimes			mp->m_len += xfer;
3911541Srgrimes			left -= xfer;
3921541Srgrimes			uiocp += xfer;
3931541Srgrimes			uiop->uio_offset += xfer;
3941541Srgrimes			uiop->uio_resid -= xfer;
3951541Srgrimes		}
3961541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
3971541Srgrimes			uiop->uio_iovcnt--;
3981541Srgrimes			uiop->uio_iov++;
3991541Srgrimes		} else {
4001541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
4011541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
4021541Srgrimes		}
4031541Srgrimes		siz -= uiosiz;
4041541Srgrimes	}
4051541Srgrimes	if (rem > 0) {
4061541Srgrimes		if (rem > M_TRAILINGSPACE(mp)) {
4071541Srgrimes			MGET(mp, M_WAIT, MT_DATA);
4081541Srgrimes			mp->m_len = 0;
4091541Srgrimes			mp2->m_next = mp;
4101541Srgrimes		}
4111541Srgrimes		cp = mtod(mp, caddr_t)+mp->m_len;
4121541Srgrimes		for (left = 0; left < rem; left++)
4131541Srgrimes			*cp++ = '\0';
4141541Srgrimes		mp->m_len += rem;
4151541Srgrimes		*bpos = cp;
4161541Srgrimes	} else
4171541Srgrimes		*bpos = mtod(mp, caddr_t)+mp->m_len;
4181541Srgrimes	*mq = mp;
4191541Srgrimes	return (0);
4201541Srgrimes}
4211541Srgrimes
4221541Srgrimes/*
4231541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous
4241541Srgrimes * pointed to by returned val.
4251541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
4261541Srgrimes * cases. (The macros use the vars. dpos and dpos2)
4271541Srgrimes */
4281549Srgrimesint
4291541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2)
4301541Srgrimes	struct mbuf **mdp;
4311541Srgrimes	caddr_t *dposp;
4321541Srgrimes	int siz;
4331541Srgrimes	int left;
4341541Srgrimes	caddr_t *cp2;
4351541Srgrimes{
4361541Srgrimes	register struct mbuf *mp, *mp2;
4371541Srgrimes	register int siz2, xfer;
4381541Srgrimes	register caddr_t p;
4391541Srgrimes
4401541Srgrimes	mp = *mdp;
4411541Srgrimes	while (left == 0) {
4421541Srgrimes		*mdp = mp = mp->m_next;
4431541Srgrimes		if (mp == NULL)
4441541Srgrimes			return (EBADRPC);
4451541Srgrimes		left = mp->m_len;
4461541Srgrimes		*dposp = mtod(mp, caddr_t);
4471541Srgrimes	}
4481541Srgrimes	if (left >= siz) {
4491541Srgrimes		*cp2 = *dposp;
4501541Srgrimes		*dposp += siz;
4511541Srgrimes	} else if (mp->m_next == NULL) {
4521541Srgrimes		return (EBADRPC);
4531541Srgrimes	} else if (siz > MHLEN) {
4541541Srgrimes		panic("nfs S too big");
4551541Srgrimes	} else {
4561541Srgrimes		MGET(mp2, M_WAIT, MT_DATA);
4571541Srgrimes		mp2->m_next = mp->m_next;
4581541Srgrimes		mp->m_next = mp2;
4591541Srgrimes		mp->m_len -= left;
4601541Srgrimes		mp = mp2;
4611541Srgrimes		*cp2 = p = mtod(mp, caddr_t);
4621541Srgrimes		bcopy(*dposp, p, left);		/* Copy what was left */
4631541Srgrimes		siz2 = siz-left;
4641541Srgrimes		p += left;
4651541Srgrimes		mp2 = mp->m_next;
4661541Srgrimes		/* Loop around copying up the siz2 bytes */
4671541Srgrimes		while (siz2 > 0) {
4681541Srgrimes			if (mp2 == NULL)
4691541Srgrimes				return (EBADRPC);
4701541Srgrimes			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
4711541Srgrimes			if (xfer > 0) {
4721541Srgrimes				bcopy(mtod(mp2, caddr_t), p, xfer);
4731541Srgrimes				NFSMADV(mp2, xfer);
4741541Srgrimes				mp2->m_len -= xfer;
4751541Srgrimes				p += xfer;
4761541Srgrimes				siz2 -= xfer;
4771541Srgrimes			}
4781541Srgrimes			if (siz2 > 0)
4791541Srgrimes				mp2 = mp2->m_next;
4801541Srgrimes		}
4811541Srgrimes		mp->m_len = siz;
4821541Srgrimes		*mdp = mp2;
4831541Srgrimes		*dposp = mtod(mp2, caddr_t);
4841541Srgrimes	}
4851541Srgrimes	return (0);
4861541Srgrimes}
4871541Srgrimes
4881541Srgrimes/*
4891541Srgrimes * Advance the position in the mbuf chain.
4901541Srgrimes */
4911549Srgrimesint
4921541Srgrimesnfs_adv(mdp, dposp, offs, left)
4931541Srgrimes	struct mbuf **mdp;
4941541Srgrimes	caddr_t *dposp;
4951541Srgrimes	int offs;
4961541Srgrimes	int left;
4971541Srgrimes{
4981541Srgrimes	register struct mbuf *m;
4991541Srgrimes	register int s;
5001541Srgrimes
5011541Srgrimes	m = *mdp;
5021541Srgrimes	s = left;
5031541Srgrimes	while (s < offs) {
5041541Srgrimes		offs -= s;
5051541Srgrimes		m = m->m_next;
5061541Srgrimes		if (m == NULL)
5071541Srgrimes			return (EBADRPC);
5081541Srgrimes		s = m->m_len;
5091541Srgrimes	}
5101541Srgrimes	*mdp = m;
5111541Srgrimes	*dposp = mtod(m, caddr_t)+offs;
5121541Srgrimes	return (0);
5131541Srgrimes}
5141541Srgrimes
5151541Srgrimes/*
5161541Srgrimes * Copy a string into mbufs for the hard cases...
5171541Srgrimes */
5181549Srgrimesint
5191541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz)
5201541Srgrimes	struct mbuf **mb;
5211541Srgrimes	char **bpos;
5221541Srgrimes	char *cp;
5231541Srgrimes	long siz;
5241541Srgrimes{
5251549Srgrimes	register struct mbuf *m1 = 0, *m2;
5261541Srgrimes	long left, xfer, len, tlen;
5271541Srgrimes	u_long *tl;
5281541Srgrimes	int putsize;
5291541Srgrimes
5301541Srgrimes	putsize = 1;
5311541Srgrimes	m2 = *mb;
5321541Srgrimes	left = M_TRAILINGSPACE(m2);
5331541Srgrimes	if (left > 0) {
5341541Srgrimes		tl = ((u_long *)(*bpos));
5351541Srgrimes		*tl++ = txdr_unsigned(siz);
5361541Srgrimes		putsize = 0;
5371541Srgrimes		left -= NFSX_UNSIGNED;
5381541Srgrimes		m2->m_len += NFSX_UNSIGNED;
5391541Srgrimes		if (left > 0) {
5401541Srgrimes			bcopy(cp, (caddr_t) tl, left);
5411541Srgrimes			siz -= left;
5421541Srgrimes			cp += left;
5431541Srgrimes			m2->m_len += left;
5441541Srgrimes			left = 0;
5451541Srgrimes		}
5461541Srgrimes	}
5471541Srgrimes	/* Loop around adding mbufs */
5481541Srgrimes	while (siz > 0) {
5491541Srgrimes		MGET(m1, M_WAIT, MT_DATA);
5501541Srgrimes		if (siz > MLEN)
5511541Srgrimes			MCLGET(m1, M_WAIT);
5521541Srgrimes		m1->m_len = NFSMSIZ(m1);
5531541Srgrimes		m2->m_next = m1;
5541541Srgrimes		m2 = m1;
5551541Srgrimes		tl = mtod(m1, u_long *);
5561541Srgrimes		tlen = 0;
5571541Srgrimes		if (putsize) {
5581541Srgrimes			*tl++ = txdr_unsigned(siz);
5591541Srgrimes			m1->m_len -= NFSX_UNSIGNED;
5601541Srgrimes			tlen = NFSX_UNSIGNED;
5611541Srgrimes			putsize = 0;
5621541Srgrimes		}
5631541Srgrimes		if (siz < m1->m_len) {
5641541Srgrimes			len = nfsm_rndup(siz);
5651541Srgrimes			xfer = siz;
5661541Srgrimes			if (xfer < len)
5671541Srgrimes				*(tl+(xfer>>2)) = 0;
5681541Srgrimes		} else {
5691541Srgrimes			xfer = len = m1->m_len;
5701541Srgrimes		}
5711541Srgrimes		bcopy(cp, (caddr_t) tl, xfer);
5721541Srgrimes		m1->m_len = len+tlen;
5731541Srgrimes		siz -= xfer;
5741541Srgrimes		cp += xfer;
5751541Srgrimes	}
5761541Srgrimes	*mb = m1;
5771541Srgrimes	*bpos = mtod(m1, caddr_t)+m1->m_len;
5781541Srgrimes	return (0);
5791541Srgrimes}
5801541Srgrimes
5811541Srgrimes/*
5821541Srgrimes * Called once to initialize data structures...
5831541Srgrimes */
5841549Srgrimesint
5851541Srgrimesnfs_init()
5861541Srgrimes{
5871541Srgrimes	register int i;
5881541Srgrimes
5891541Srgrimes	nfsrtt.pos = 0;
5901541Srgrimes	rpc_vers = txdr_unsigned(RPC_VER2);
5911541Srgrimes	rpc_call = txdr_unsigned(RPC_CALL);
5921541Srgrimes	rpc_reply = txdr_unsigned(RPC_REPLY);
5931541Srgrimes	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
5941541Srgrimes	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
5951541Srgrimes	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
5961541Srgrimes	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
5971541Srgrimes	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
5981541Srgrimes	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
5991541Srgrimes	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
6001541Srgrimes	nfs_vers = txdr_unsigned(NFS_VER2);
6011541Srgrimes	nfs_prog = txdr_unsigned(NFS_PROG);
6021541Srgrimes	nfs_true = txdr_unsigned(TRUE);
6031541Srgrimes	nfs_false = txdr_unsigned(FALSE);
6041541Srgrimes	/* Loop thru nfs procids */
6051541Srgrimes	for (i = 0; i < NFS_NPROCS; i++)
6061541Srgrimes		nfs_procids[i] = txdr_unsigned(i);
6071541Srgrimes	/* Ensure async daemons disabled */
6081541Srgrimes	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
6091541Srgrimes		nfs_iodwant[i] = (struct proc *)0;
6101541Srgrimes	TAILQ_INIT(&nfs_bufq);
6111541Srgrimes	nfs_xdrneg1 = txdr_unsigned(-1);
6121541Srgrimes	nfs_nhinit();			/* Init the nfsnode table */
6131541Srgrimes	nfsrv_init(0);			/* Init server data structures */
6141541Srgrimes	nfsrv_initcache();		/* Init the server request cache */
6151541Srgrimes
6161541Srgrimes	/*
6171541Srgrimes	 * Initialize the nqnfs server stuff.
6181541Srgrimes	 */
6191541Srgrimes	if (nqnfsstarttime == 0) {
6201541Srgrimes		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
6211541Srgrimes			+ nqsrv_clockskew + nqsrv_writeslack;
6221541Srgrimes		NQLOADNOVRAM(nqnfsstarttime);
6231541Srgrimes		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
6241541Srgrimes		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
6251541Srgrimes		nqthead.th_head[0] = &nqthead;
6261541Srgrimes		nqthead.th_head[1] = &nqthead;
6271541Srgrimes		nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash);
6281541Srgrimes	}
6291541Srgrimes
6301541Srgrimes	/*
6311541Srgrimes	 * Initialize reply list and start timer
6321541Srgrimes	 */
6331541Srgrimes	nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
6341541Srgrimes	nfs_timer();
6351549Srgrimes
6361549Srgrimes	return (0);
6371541Srgrimes}
6381541Srgrimes
6391541Srgrimes/*
6401541Srgrimes * Attribute cache routines.
6411541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes
6421541Srgrimes *	that are on the mbuf list
6431541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns
6441541Srgrimes *	error otherwise
6451541Srgrimes */
6461541Srgrimes
6471541Srgrimes/*
6481541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with
6491541Srgrimes * the values on the mbuf list and
6501541Srgrimes * Iff vap not NULL
6511541Srgrimes *    copy the attributes to *vaper
6521541Srgrimes */
6531549Srgrimesint
6541541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper)
6551541Srgrimes	struct vnode **vpp;
6561541Srgrimes	struct mbuf **mdp;
6571541Srgrimes	caddr_t *dposp;
6581541Srgrimes	struct vattr *vaper;
6591541Srgrimes{
6601541Srgrimes	register struct vnode *vp = *vpp;
6611541Srgrimes	register struct vattr *vap;
6621541Srgrimes	register struct nfsv2_fattr *fp;
6631541Srgrimes	extern int (**spec_nfsv2nodeop_p)();
6641541Srgrimes	register struct nfsnode *np, *nq, **nhpp;
6651541Srgrimes	register long t1;
6661541Srgrimes	caddr_t dpos, cp2;
6671541Srgrimes	int error = 0, isnq;
6681541Srgrimes	struct mbuf *md;
6691541Srgrimes	enum vtype vtyp;
6701541Srgrimes	u_short vmode;
6711541Srgrimes	long rdev;
6721541Srgrimes	struct timespec mtime;
6731541Srgrimes	struct vnode *nvp;
6741541Srgrimes
6751541Srgrimes	md = *mdp;
6761541Srgrimes	dpos = *dposp;
6771541Srgrimes	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
6781541Srgrimes	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
6791541Srgrimes	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2))
6801541Srgrimes		return (error);
6811541Srgrimes	fp = (struct nfsv2_fattr *)cp2;
6821541Srgrimes	vtyp = nfstov_type(fp->fa_type);
6831541Srgrimes	vmode = fxdr_unsigned(u_short, fp->fa_mode);
6841541Srgrimes	if (vtyp == VNON || vtyp == VREG)
6851541Srgrimes		vtyp = IFTOVT(vmode);
6861541Srgrimes	if (isnq) {
6871541Srgrimes		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
6881541Srgrimes		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
6891541Srgrimes	} else {
6901541Srgrimes		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
6911541Srgrimes		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
6921541Srgrimes	}
6931541Srgrimes	/*
6941541Srgrimes	 * If v_type == VNON it is a new node, so fill in the v_type,
6951541Srgrimes	 * n_mtime fields. Check to see if it represents a special
6961541Srgrimes	 * device, and if so, check for a possible alias. Once the
6971541Srgrimes	 * correct vnode has been obtained, fill in the rest of the
6981541Srgrimes	 * information.
6991541Srgrimes	 */
7001541Srgrimes	np = VTONFS(vp);
7011541Srgrimes	if (vp->v_type == VNON) {
7021541Srgrimes		if (vtyp == VCHR && rdev == 0xffffffff)
7031541Srgrimes			vp->v_type = vtyp = VFIFO;
7041541Srgrimes		else
7051541Srgrimes			vp->v_type = vtyp;
7061541Srgrimes		if (vp->v_type == VFIFO) {
7071541Srgrimes#ifdef FIFO
7081541Srgrimes			extern int (**fifo_nfsv2nodeop_p)();
7091541Srgrimes			vp->v_op = fifo_nfsv2nodeop_p;
7101541Srgrimes#else
7111541Srgrimes			return (EOPNOTSUPP);
7121541Srgrimes#endif /* FIFO */
7131541Srgrimes		}
7141541Srgrimes		if (vp->v_type == VCHR || vp->v_type == VBLK) {
7151541Srgrimes			vp->v_op = spec_nfsv2nodeop_p;
7161541Srgrimes			if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
7171541Srgrimes				/*
7181541Srgrimes				 * Discard unneeded vnode, but save its nfsnode.
7191541Srgrimes				 */
7201541Srgrimes				if (nq = np->n_forw)
7211541Srgrimes					nq->n_back = np->n_back;
7221541Srgrimes				*np->n_back = nq;
7231541Srgrimes				nvp->v_data = vp->v_data;
7241541Srgrimes				vp->v_data = NULL;
7251541Srgrimes				vp->v_op = spec_vnodeop_p;
7261541Srgrimes				vrele(vp);
7271541Srgrimes				vgone(vp);
7281541Srgrimes				/*
7291541Srgrimes				 * Reinitialize aliased node.
7301541Srgrimes				 */
7311541Srgrimes				np->n_vnode = nvp;
7321541Srgrimes				nhpp = (struct nfsnode **)nfs_hash(&np->n_fh);
7331541Srgrimes				if (nq = *nhpp)
7341541Srgrimes					nq->n_back = &np->n_forw;
7351541Srgrimes				np->n_forw = nq;
7361541Srgrimes				np->n_back = nhpp;
7371541Srgrimes				*nhpp = np;
7381541Srgrimes				*vpp = vp = nvp;
7391541Srgrimes			}
7401541Srgrimes		}
7411541Srgrimes		np->n_mtime = mtime.ts_sec;
7421541Srgrimes	}
7431541Srgrimes	vap = &np->n_vattr;
7441541Srgrimes	vap->va_type = vtyp;
7451541Srgrimes	vap->va_mode = (vmode & 07777);
7461541Srgrimes	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
7471541Srgrimes	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
7481541Srgrimes	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
7491541Srgrimes	vap->va_rdev = (dev_t)rdev;
7501541Srgrimes	vap->va_mtime = mtime;
7511541Srgrimes	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
7521541Srgrimes	if (isnq) {
7531541Srgrimes		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
7541541Srgrimes		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
7551541Srgrimes		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
7561541Srgrimes		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
7571541Srgrimes		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
7581541Srgrimes		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
7591541Srgrimes		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
7601541Srgrimes		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
7611541Srgrimes		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
7621541Srgrimes	} else {
7631541Srgrimes		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
7641541Srgrimes		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
7651541Srgrimes		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
7661541Srgrimes		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
7671541Srgrimes		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
7681541Srgrimes		vap->va_flags = 0;
7691541Srgrimes		vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec);
7701541Srgrimes		vap->va_ctime.ts_nsec = 0;
7711541Srgrimes		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec);
7721541Srgrimes		vap->va_filerev = 0;
7731541Srgrimes	}
7741541Srgrimes	if (vap->va_size != np->n_size) {
7751541Srgrimes		if (vap->va_type == VREG) {
7761541Srgrimes			if (np->n_flag & NMODIFIED) {
7771541Srgrimes				if (vap->va_size < np->n_size)
7781541Srgrimes					vap->va_size = np->n_size;
7791541Srgrimes				else
7801541Srgrimes					np->n_size = vap->va_size;
7811541Srgrimes			} else
7821541Srgrimes				np->n_size = vap->va_size;
7831541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
7841541Srgrimes		} else
7851541Srgrimes			np->n_size = vap->va_size;
7861541Srgrimes	}
7871541Srgrimes	np->n_attrstamp = time.tv_sec;
7881541Srgrimes	*dposp = dpos;
7891541Srgrimes	*mdp = md;
7901541Srgrimes	if (vaper != NULL) {
7911541Srgrimes		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
7921541Srgrimes#ifdef notdef
7931541Srgrimes		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
7941541Srgrimes		if (np->n_size > vap->va_size)
7951541Srgrimes			vaper->va_size = np->n_size;
7961541Srgrimes#endif
7971541Srgrimes		if (np->n_flag & NCHG) {
7981541Srgrimes			if (np->n_flag & NACC) {
7991541Srgrimes				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
8001541Srgrimes				vaper->va_atime.ts_nsec =
8011541Srgrimes				    np->n_atim.tv_usec * 1000;
8021541Srgrimes			}
8031541Srgrimes			if (np->n_flag & NUPD) {
8041541Srgrimes				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
8051541Srgrimes				vaper->va_mtime.ts_nsec =
8061541Srgrimes				    np->n_mtim.tv_usec * 1000;
8071541Srgrimes			}
8081541Srgrimes		}
8091541Srgrimes	}
8101541Srgrimes	return (0);
8111541Srgrimes}
8121541Srgrimes
8131541Srgrimes/*
8141541Srgrimes * Check the time stamp
8151541Srgrimes * If the cache is valid, copy contents to *vap and return 0
8161541Srgrimes * otherwise return an error
8171541Srgrimes */
8181549Srgrimesint
8191541Srgrimesnfs_getattrcache(vp, vaper)
8201541Srgrimes	register struct vnode *vp;
8211541Srgrimes	struct vattr *vaper;
8221541Srgrimes{
8231541Srgrimes	register struct nfsnode *np = VTONFS(vp);
8241541Srgrimes	register struct vattr *vap;
8251541Srgrimes
8261541Srgrimes	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
8271541Srgrimes		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
8281541Srgrimes			nfsstats.attrcache_misses++;
8291541Srgrimes			return (ENOENT);
8301541Srgrimes		}
8311541Srgrimes	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
8321541Srgrimes		nfsstats.attrcache_misses++;
8331541Srgrimes		return (ENOENT);
8341541Srgrimes	}
8351541Srgrimes	nfsstats.attrcache_hits++;
8361541Srgrimes	vap = &np->n_vattr;
8371541Srgrimes	if (vap->va_size != np->n_size) {
8381541Srgrimes		if (vap->va_type == VREG) {
8391541Srgrimes			if (np->n_flag & NMODIFIED) {
8401541Srgrimes				if (vap->va_size < np->n_size)
8411541Srgrimes					vap->va_size = np->n_size;
8421541Srgrimes				else
8431541Srgrimes					np->n_size = vap->va_size;
8441541Srgrimes			} else
8451541Srgrimes				np->n_size = vap->va_size;
8461541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
8471541Srgrimes		} else
8481541Srgrimes			np->n_size = vap->va_size;
8491541Srgrimes	}
8501541Srgrimes	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
8511541Srgrimes#ifdef notdef
8521541Srgrimes	if ((np->n_flag & NMODIFIED) == 0) {
8531541Srgrimes		np->n_size = vaper->va_size;
8541541Srgrimes		vnode_pager_setsize(vp, (u_long)np->n_size);
8551541Srgrimes	} else if (np->n_size > vaper->va_size)
8561541Srgrimes	if (np->n_size > vaper->va_size)
8571541Srgrimes		vaper->va_size = np->n_size;
8581541Srgrimes#endif
8591541Srgrimes	if (np->n_flag & NCHG) {
8601541Srgrimes		if (np->n_flag & NACC) {
8611541Srgrimes			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
8621541Srgrimes			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
8631541Srgrimes		}
8641541Srgrimes		if (np->n_flag & NUPD) {
8651541Srgrimes			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
8661541Srgrimes			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
8671541Srgrimes		}
8681541Srgrimes	}
8691541Srgrimes	return (0);
8701541Srgrimes}
8711541Srgrimes
8721541Srgrimes/*
8731541Srgrimes * Set up nameidata for a lookup() call and do it
8741541Srgrimes */
8751549Srgrimesint
8761541Srgrimesnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
8771541Srgrimes	register struct nameidata *ndp;
8781541Srgrimes	fhandle_t *fhp;
8791541Srgrimes	int len;
8801541Srgrimes	struct nfssvc_sock *slp;
8811541Srgrimes	struct mbuf *nam;
8821541Srgrimes	struct mbuf **mdp;
8831541Srgrimes	caddr_t *dposp;
8841541Srgrimes	struct proc *p;
8851541Srgrimes{
8861541Srgrimes	register int i, rem;
8871541Srgrimes	register struct mbuf *md;
8881541Srgrimes	register char *fromcp, *tocp;
8891541Srgrimes	struct vnode *dp;
8901541Srgrimes	int error, rdonly;
8911541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
8921541Srgrimes
8931541Srgrimes	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
8941541Srgrimes	/*
8951541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
8961541Srgrimes	 * and set the various ndp fields appropriately.
8971541Srgrimes	 */
8981541Srgrimes	fromcp = *dposp;
8991541Srgrimes	tocp = cnp->cn_pnbuf;
9001541Srgrimes	md = *mdp;
9011541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
9021541Srgrimes	cnp->cn_hash = 0;
9031541Srgrimes	for (i = 0; i < len; i++) {
9041541Srgrimes		while (rem == 0) {
9051541Srgrimes			md = md->m_next;
9061541Srgrimes			if (md == NULL) {
9071541Srgrimes				error = EBADRPC;
9081541Srgrimes				goto out;
9091541Srgrimes			}
9101541Srgrimes			fromcp = mtod(md, caddr_t);
9111541Srgrimes			rem = md->m_len;
9121541Srgrimes		}
9131541Srgrimes		if (*fromcp == '\0' || *fromcp == '/') {
9141541Srgrimes			error = EINVAL;
9151541Srgrimes			goto out;
9161541Srgrimes		}
9171541Srgrimes		cnp->cn_hash += (unsigned char)*fromcp;
9181541Srgrimes		*tocp++ = *fromcp++;
9191541Srgrimes		rem--;
9201541Srgrimes	}
9211541Srgrimes	*tocp = '\0';
9221541Srgrimes	*mdp = md;
9231541Srgrimes	*dposp = fromcp;
9241541Srgrimes	len = nfsm_rndup(len)-len;
9251541Srgrimes	if (len > 0) {
9261541Srgrimes		if (rem >= len)
9271541Srgrimes			*dposp += len;
9281541Srgrimes		else if (error = nfs_adv(mdp, dposp, len, rem))
9291541Srgrimes			goto out;
9301541Srgrimes	}
9311541Srgrimes	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
9321541Srgrimes	cnp->cn_nameptr = cnp->cn_pnbuf;
9331541Srgrimes	/*
9341541Srgrimes	 * Extract and set starting directory.
9351541Srgrimes	 */
9361541Srgrimes	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
9371541Srgrimes	    nam, &rdonly))
9381541Srgrimes		goto out;
9391541Srgrimes	if (dp->v_type != VDIR) {
9401541Srgrimes		vrele(dp);
9411541Srgrimes		error = ENOTDIR;
9421541Srgrimes		goto out;
9431541Srgrimes	}
9441541Srgrimes	ndp->ni_startdir = dp;
9451541Srgrimes	if (rdonly)
9461541Srgrimes		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
9471541Srgrimes	else
9481541Srgrimes		cnp->cn_flags |= NOCROSSMOUNT;
9491541Srgrimes	/*
9501541Srgrimes	 * And call lookup() to do the real work
9511541Srgrimes	 */
9521541Srgrimes	cnp->cn_proc = p;
9531541Srgrimes	if (error = lookup(ndp))
9541541Srgrimes		goto out;
9551541Srgrimes	/*
9561541Srgrimes	 * Check for encountering a symbolic link
9571541Srgrimes	 */
9581541Srgrimes	if (cnp->cn_flags & ISSYMLINK) {
9591541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
9601541Srgrimes			vput(ndp->ni_dvp);
9611541Srgrimes		else
9621541Srgrimes			vrele(ndp->ni_dvp);
9631541Srgrimes		vput(ndp->ni_vp);
9641541Srgrimes		ndp->ni_vp = NULL;
9651541Srgrimes		error = EINVAL;
9661541Srgrimes		goto out;
9671541Srgrimes	}
9681541Srgrimes	/*
9691541Srgrimes	 * Check for saved name request
9701541Srgrimes	 */
9711541Srgrimes	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
9721541Srgrimes		cnp->cn_flags |= HASBUF;
9731541Srgrimes		return (0);
9741541Srgrimes	}
9751541Srgrimesout:
9761541Srgrimes	FREE(cnp->cn_pnbuf, M_NAMEI);
9771541Srgrimes	return (error);
9781541Srgrimes}
9791541Srgrimes
9801541Srgrimes/*
9811541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
9821541Srgrimes * boundary and only trims off the back end
9831541Srgrimes */
9841541Srgrimesvoid
9851541Srgrimesnfsm_adj(mp, len, nul)
9861541Srgrimes	struct mbuf *mp;
9871541Srgrimes	register int len;
9881541Srgrimes	int nul;
9891541Srgrimes{
9901541Srgrimes	register struct mbuf *m;
9911541Srgrimes	register int count, i;
9921541Srgrimes	register char *cp;
9931541Srgrimes
9941541Srgrimes	/*
9951541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
9961541Srgrimes	 * calculating its length and finding the last mbuf.
9971541Srgrimes	 * If the adjustment only affects this mbuf, then just
9981541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
9991541Srgrimes	 * after the remaining size.
10001541Srgrimes	 */
10011541Srgrimes	count = 0;
10021541Srgrimes	m = mp;
10031541Srgrimes	for (;;) {
10041541Srgrimes		count += m->m_len;
10051541Srgrimes		if (m->m_next == (struct mbuf *)0)
10061541Srgrimes			break;
10071541Srgrimes		m = m->m_next;
10081541Srgrimes	}
10091541Srgrimes	if (m->m_len > len) {
10101541Srgrimes		m->m_len -= len;
10111541Srgrimes		if (nul > 0) {
10121541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
10131541Srgrimes			for (i = 0; i < nul; i++)
10141541Srgrimes				*cp++ = '\0';
10151541Srgrimes		}
10161541Srgrimes		return;
10171541Srgrimes	}
10181541Srgrimes	count -= len;
10191541Srgrimes	if (count < 0)
10201541Srgrimes		count = 0;
10211541Srgrimes	/*
10221541Srgrimes	 * Correct length for chain is "count".
10231541Srgrimes	 * Find the mbuf with last data, adjust its length,
10241541Srgrimes	 * and toss data from remaining mbufs on chain.
10251541Srgrimes	 */
10261541Srgrimes	for (m = mp; m; m = m->m_next) {
10271541Srgrimes		if (m->m_len >= count) {
10281541Srgrimes			m->m_len = count;
10291541Srgrimes			if (nul > 0) {
10301541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
10311541Srgrimes				for (i = 0; i < nul; i++)
10321541Srgrimes					*cp++ = '\0';
10331541Srgrimes			}
10341541Srgrimes			break;
10351541Srgrimes		}
10361541Srgrimes		count -= m->m_len;
10371541Srgrimes	}
10381541Srgrimes	while (m = m->m_next)
10391541Srgrimes		m->m_len = 0;
10401541Srgrimes}
10411541Srgrimes
10421541Srgrimes/*
10431541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
10441541Srgrimes * 	- look up fsid in mount list (if not found ret error)
10451541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
10461541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
10471541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
10481541Srgrimes */
10491549Srgrimesint
10501541Srgrimesnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
10511541Srgrimes	fhandle_t *fhp;
10521541Srgrimes	int lockflag;
10531541Srgrimes	struct vnode **vpp;
10541541Srgrimes	struct ucred *cred;
10551541Srgrimes	struct nfssvc_sock *slp;
10561541Srgrimes	struct mbuf *nam;
10571541Srgrimes	int *rdonlyp;
10581541Srgrimes{
10591541Srgrimes	register struct mount *mp;
10601541Srgrimes	register struct nfsuid *uidp;
10611541Srgrimes	register int i;
10621541Srgrimes	struct ucred *credanon;
10631541Srgrimes	int error, exflags;
10641541Srgrimes
10651541Srgrimes	*vpp = (struct vnode *)0;
10661541Srgrimes	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
10671541Srgrimes		return (ESTALE);
10681541Srgrimes	if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon))
10691541Srgrimes		return (error);
10701541Srgrimes	/*
10711541Srgrimes	 * Check/setup credentials.
10721541Srgrimes	 */
10731541Srgrimes	if (exflags & MNT_EXKERB) {
10741541Srgrimes		uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
10751541Srgrimes		while (uidp) {
10761541Srgrimes			if (uidp->nu_uid == cred->cr_uid)
10771541Srgrimes				break;
10781541Srgrimes			uidp = uidp->nu_hnext;
10791541Srgrimes		}
10801541Srgrimes		if (uidp) {
10811541Srgrimes			cred->cr_uid = uidp->nu_cr.cr_uid;
10821541Srgrimes			for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
10831541Srgrimes				cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
10841541Srgrimes		} else {
10851541Srgrimes			vput(*vpp);
10861541Srgrimes			return (NQNFS_AUTHERR);
10871541Srgrimes		}
10881541Srgrimes	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
10891541Srgrimes		cred->cr_uid = credanon->cr_uid;
10901541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
10911541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
10921541Srgrimes	}
10931541Srgrimes	if (exflags & MNT_EXRDONLY)
10941541Srgrimes		*rdonlyp = 1;
10951541Srgrimes	else
10961541Srgrimes		*rdonlyp = 0;
10971541Srgrimes	if (!lockflag)
10981541Srgrimes		VOP_UNLOCK(*vpp);
10991541Srgrimes	return (0);
11001541Srgrimes}
11011541Srgrimes
11021541Srgrimes/*
11031541Srgrimes * This function compares two net addresses by family and returns TRUE
11041541Srgrimes * if they are the same host.
11051541Srgrimes * If there is any doubt, return FALSE.
11061541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
11071541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
11081541Srgrimes */
11091549Srgrimesint
11101541Srgrimesnetaddr_match(family, haddr, nam)
11111541Srgrimes	int family;
11121541Srgrimes	union nethostaddr *haddr;
11131541Srgrimes	struct mbuf *nam;
11141541Srgrimes{
11151541Srgrimes	register struct sockaddr_in *inetaddr;
11161541Srgrimes
11171541Srgrimes	switch (family) {
11181541Srgrimes	case AF_INET:
11191541Srgrimes		inetaddr = mtod(nam, struct sockaddr_in *);
11201541Srgrimes		if (inetaddr->sin_family == AF_INET &&
11211541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
11221541Srgrimes			return (1);
11231541Srgrimes		break;
11241541Srgrimes#ifdef ISO
11251541Srgrimes	case AF_ISO:
11261541Srgrimes	    {
11271541Srgrimes		register struct sockaddr_iso *isoaddr1, *isoaddr2;
11281541Srgrimes
11291541Srgrimes		isoaddr1 = mtod(nam, struct sockaddr_iso *);
11301541Srgrimes		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
11311541Srgrimes		if (isoaddr1->siso_family == AF_ISO &&
11321541Srgrimes		    isoaddr1->siso_nlen > 0 &&
11331541Srgrimes		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
11341541Srgrimes		    SAME_ISOADDR(isoaddr1, isoaddr2))
11351541Srgrimes			return (1);
11361541Srgrimes		break;
11371541Srgrimes	    }
11381541Srgrimes#endif	/* ISO */
11391541Srgrimes	default:
11401541Srgrimes		break;
11411541Srgrimes	};
11421541Srgrimes	return (0);
11431541Srgrimes}
1144