nfs_srvsubs.c revision 2997
1234370Sjasone/*
2234370Sjasone * Copyright (c) 1989, 1993
3234370Sjasone *	The Regents of the University of California.  All rights reserved.
4234370Sjasone *
5251300Sjasone * This code is derived from software contributed to Berkeley by
6234370Sjasone * Rick Macklem at The University of Guelph.
7251300Sjasone *
8234370Sjasone * Redistribution and use in source and binary forms, with or without
9234370Sjasone * modification, are permitted provided that the following conditions
10251300Sjasone * are met:
11234370Sjasone * 1. Redistributions of source code must retain the above copyright
12234370Sjasone *    notice, this list of conditions and the following disclaimer.
13234370Sjasone * 2. Redistributions in binary form must reproduce the above copyright
14234370Sjasone *    notice, this list of conditions and the following disclaimer in the
15234370Sjasone *    documentation and/or other materials provided with the distribution.
16234370Sjasone * 3. All advertising materials mentioning features or use of this software
17234370Sjasone *    must display the following acknowledgement:
18234370Sjasone *	This product includes software developed by the University of
19234370Sjasone *	California, Berkeley and its contributors.
20234370Sjasone * 4. Neither the name of the University nor the names of its contributors
21234370Sjasone *    may be used to endorse or promote products derived from this software
22234370Sjasone *    without specific prior written permission.
23234370Sjasone *
24234370Sjasone * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25234370Sjasone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26234370Sjasone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27234370Sjasone * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28234370Sjasone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29234370Sjasone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30234370Sjasone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31234370Sjasone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32234370Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33234370Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34251300Sjasone * SUCH DAMAGE.
35234370Sjasone *
36234370Sjasone *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
37234370Sjasone * $Id: nfs_subs.c,v 1.3 1994/08/02 07:52:13 davidg Exp $
38234370Sjasone */
39234370Sjasone
40234370Sjasone/*
41234370Sjasone * These functions support the macros and help fiddle mbuf chains for
42234370Sjasone * the nfs op functions. They do things like create the rpc header and
43234370Sjasone * copy data between mbuf chains and uio lists.
44234370Sjasone */
45234370Sjasone#include <sys/param.h>
46234370Sjasone#include <sys/proc.h>
47234370Sjasone#include <sys/systm.h>
48234370Sjasone#include <sys/kernel.h>
49234370Sjasone#include <sys/mount.h>
50234370Sjasone#include <sys/vnode.h>
51234370Sjasone#include <sys/namei.h>
52234370Sjasone#include <sys/mbuf.h>
53234370Sjasone#include <sys/socket.h>
54234370Sjasone#include <sys/stat.h>
55234370Sjasone#ifdef VFS_LKM
56234370Sjasone#include <sys/sysent.h>
57234370Sjasone#include <sys/syscall.h>
58234370Sjasone#endif
59234370Sjasone
60234370Sjasone#include <nfs/rpcv2.h>
61234370Sjasone#include <nfs/nfsv2.h>
62234370Sjasone#include <nfs/nfsnode.h>
63234370Sjasone#include <nfs/nfs.h>
64234370Sjasone#include <nfs/xdr_subs.h>
65234370Sjasone#include <nfs/nfsm_subs.h>
66234370Sjasone#include <nfs/nfsmount.h>
67234370Sjasone#include <nfs/nqnfs.h>
68234370Sjasone#include <nfs/nfsrtt.h>
69234370Sjasone
70234370Sjasone#include <miscfs/specfs/specdev.h>
71234370Sjasone
72234370Sjasone#include <netinet/in.h>
73234370Sjasone#ifdef ISO
74234370Sjasone#include <netiso/iso.h>
75234370Sjasone#endif
76234370Sjasone
77234370Sjasone#define TRUE	1
78234370Sjasone#define	FALSE	0
79234370Sjasone
80234370Sjasone/*
81234370Sjasone * Data items converted to xdr at startup, since they are constant
82234370Sjasone * This is kinda hokey, but may save a little time doing byte swaps
83234370Sjasone */
84234370Sjasoneu_long nfs_procids[NFS_NPROCS];
85234370Sjasoneu_long nfs_xdrneg1;
86234370Sjasoneu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
87234370Sjasone	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
88234370Sjasone	rpc_auth_kerb;
89234370Sjasoneu_long nfs_vers, nfs_prog, nfs_true, nfs_false;
90234370Sjasone
91234370Sjasone/* And other global data */
92234370Sjasonestatic u_long nfs_xid = 0;
93234370Sjasoneenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
94234370Sjasoneextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
95234370Sjasoneextern struct nfsreq nfsreqh;
96234370Sjasoneextern int nqnfs_piggy[NFS_NPROCS];
97234370Sjasoneextern struct nfsrtt nfsrtt;
98234370Sjasoneextern time_t nqnfsstarttime;
99234370Sjasoneextern u_long nqnfs_prog, nqnfs_vers;
100234370Sjasoneextern int nqsrv_clockskew;
101234370Sjasoneextern int nqsrv_writeslack;
102234370Sjasoneextern int nqsrv_maxlease;
103234370Sjasone
104234370Sjasone#ifdef VFS_LKM
105234370Sjasonestruct getfh_args;
106234370Sjasoneextern int getfh(struct proc *, struct getfh_args *, int *);
107234370Sjasonestruct nfssvc_args;
108234370Sjasoneextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
109234370Sjasone#endif
110234370Sjasone
111234370Sjasone/*
112234370Sjasone * Create the header for an rpc request packet
113234370Sjasone * The hsiz is the size of the rest of the nfs request header.
114234370Sjasone * (just used to decide if a cluster is a good idea)
115234370Sjasone */
116234370Sjasonestruct mbuf *
117234370Sjasonenfsm_reqh(vp, procid, hsiz, bposp)
118234370Sjasone	struct vnode *vp;
119234370Sjasone	u_long procid;
120234370Sjasone	int hsiz;
121234370Sjasone	caddr_t *bposp;
122234370Sjasone{
123234370Sjasone	register struct mbuf *mb;
124234370Sjasone	register u_long *tl;
125234370Sjasone	register caddr_t bpos;
126234370Sjasone	struct mbuf *mb2;
127234370Sjasone	struct nfsmount *nmp;
128234370Sjasone	int nqflag;
129234370Sjasone
130234370Sjasone	MGET(mb, M_WAIT, MT_DATA);
131234370Sjasone	if (hsiz >= MINCLSIZE)
132234370Sjasone		MCLGET(mb, M_WAIT);
133234370Sjasone	mb->m_len = 0;
134234370Sjasone	bpos = mtod(mb, caddr_t);
135234370Sjasone
136234370Sjasone	/*
137234370Sjasone	 * For NQNFS, add lease request.
138234370Sjasone	 */
139234370Sjasone	if (vp) {
140234370Sjasone		nmp = VFSTONFS(vp->v_mount);
141234370Sjasone		if (nmp->nm_flag & NFSMNT_NQNFS) {
142234370Sjasone			nqflag = NQNFS_NEEDLEASE(vp, procid);
143234370Sjasone			if (nqflag) {
144234370Sjasone				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
145234370Sjasone				*tl++ = txdr_unsigned(nqflag);
146234370Sjasone				*tl = txdr_unsigned(nmp->nm_leaseterm);
147234370Sjasone			} else {
148234370Sjasone				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
149234370Sjasone				*tl = 0;
150234370Sjasone			}
151234370Sjasone		}
152234370Sjasone	}
153234370Sjasone	/* Finally, return values */
154234370Sjasone	*bposp = bpos;
155234370Sjasone	return (mb);
156234370Sjasone}
157234370Sjasone
158234370Sjasone/*
159234370Sjasone * Build the RPC header and fill in the authorization info.
160234370Sjasone * The authorization string argument is only used when the credentials
161234370Sjasone * come from outside of the kernel.
162234370Sjasone * Returns the head of the mbuf list.
163234370Sjasone */
164234370Sjasonestruct mbuf *
165234370Sjasonenfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
166234370Sjasone	mrest_len, mbp, xidp)
167234370Sjasone	register struct ucred *cr;
168234370Sjasone	int nqnfs;
169234370Sjasone	int procid;
170234370Sjasone	int auth_type;
171234370Sjasone	int auth_len;
172234370Sjasone	char *auth_str;
173234370Sjasone	struct mbuf *mrest;
174234370Sjasone	int mrest_len;
175234370Sjasone	struct mbuf **mbp;
176234370Sjasone	u_long *xidp;
177234370Sjasone{
178234370Sjasone	register struct mbuf *mb;
179234370Sjasone	register u_long *tl;
180234370Sjasone	register caddr_t bpos;
181234370Sjasone	register int i;
182234370Sjasone	struct mbuf *mreq, *mb2;
183234370Sjasone	int siz, grpsiz, authsiz;
184234370Sjasone
185234370Sjasone	authsiz = nfsm_rndup(auth_len);
186234370Sjasone	if (auth_type == RPCAUTH_NQNFS)
187234370Sjasone		authsiz += 2 * NFSX_UNSIGNED;
188234370Sjasone	MGETHDR(mb, M_WAIT, MT_DATA);
189234370Sjasone	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
190234370Sjasone		MCLGET(mb, M_WAIT);
191234370Sjasone	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
192234370Sjasone		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
193234370Sjasone	} else {
194234370Sjasone		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
195234370Sjasone	}
196234370Sjasone	mb->m_len = 0;
197234370Sjasone	mreq = mb;
198234370Sjasone	bpos = mtod(mb, caddr_t);
199234370Sjasone
200234370Sjasone	/*
201234370Sjasone	 * First the RPC header.
202234370Sjasone	 */
203234370Sjasone	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
204234370Sjasone	if (++nfs_xid == 0)
205234370Sjasone		nfs_xid++;
206234370Sjasone	*tl++ = *xidp = txdr_unsigned(nfs_xid);
207234370Sjasone	*tl++ = rpc_call;
208234370Sjasone	*tl++ = rpc_vers;
209234370Sjasone	if (nqnfs) {
210234370Sjasone		*tl++ = txdr_unsigned(NQNFS_PROG);
211234370Sjasone		*tl++ = txdr_unsigned(NQNFS_VER1);
212234370Sjasone	} else {
213234370Sjasone		*tl++ = txdr_unsigned(NFS_PROG);
214234370Sjasone		*tl++ = txdr_unsigned(NFS_VER2);
215234370Sjasone	}
216234370Sjasone	*tl++ = txdr_unsigned(procid);
217234370Sjasone
218234370Sjasone	/*
219234370Sjasone	 * And then the authorization cred.
220234370Sjasone	 */
221234370Sjasone	*tl++ = txdr_unsigned(auth_type);
222234370Sjasone	*tl = txdr_unsigned(authsiz);
223234370Sjasone	switch (auth_type) {
224234370Sjasone	case RPCAUTH_UNIX:
225234370Sjasone		nfsm_build(tl, u_long *, auth_len);
226234370Sjasone		*tl++ = 0;		/* stamp ?? */
227234370Sjasone		*tl++ = 0;		/* NULL hostname */
228234370Sjasone		*tl++ = txdr_unsigned(cr->cr_uid);
229234370Sjasone		*tl++ = txdr_unsigned(cr->cr_groups[0]);
230234370Sjasone		grpsiz = (auth_len >> 2) - 5;
231234370Sjasone		*tl++ = txdr_unsigned(grpsiz);
232234370Sjasone		for (i = 1; i <= grpsiz; i++)
233234370Sjasone			*tl++ = txdr_unsigned(cr->cr_groups[i]);
234234370Sjasone		break;
235234370Sjasone	case RPCAUTH_NQNFS:
236234370Sjasone		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
237234370Sjasone		*tl++ = txdr_unsigned(cr->cr_uid);
238234370Sjasone		*tl = txdr_unsigned(auth_len);
239234370Sjasone		siz = auth_len;
240234370Sjasone		while (siz > 0) {
241234370Sjasone			if (M_TRAILINGSPACE(mb) == 0) {
242234370Sjasone				MGET(mb2, M_WAIT, MT_DATA);
243234370Sjasone				if (siz >= MINCLSIZE)
244234370Sjasone					MCLGET(mb2, M_WAIT);
245234370Sjasone				mb->m_next = mb2;
246234370Sjasone				mb = mb2;
247234370Sjasone				mb->m_len = 0;
248234370Sjasone				bpos = mtod(mb, caddr_t);
249234370Sjasone			}
250234370Sjasone			i = min(siz, M_TRAILINGSPACE(mb));
251234370Sjasone			bcopy(auth_str, bpos, i);
252234370Sjasone			mb->m_len += i;
253234370Sjasone			auth_str += i;
254234370Sjasone			bpos += i;
255234370Sjasone			siz -= i;
256234370Sjasone		}
257234370Sjasone		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
258234370Sjasone			for (i = 0; i < siz; i++)
259234370Sjasone				*bpos++ = '\0';
260234370Sjasone			mb->m_len += siz;
261234370Sjasone		}
262234370Sjasone		break;
263234370Sjasone	};
264234370Sjasone	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
265234370Sjasone	*tl++ = txdr_unsigned(RPCAUTH_NULL);
266234370Sjasone	*tl = 0;
267234370Sjasone	mb->m_next = mrest;
268234370Sjasone	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
269234370Sjasone	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
270234370Sjasone	*mbp = mb;
271234370Sjasone	return (mreq);
272234370Sjasone}
273234370Sjasone
274234370Sjasone/*
275234370Sjasone * copies mbuf chain to the uio scatter/gather list
276234370Sjasone */
277234370Sjasoneint
278234370Sjasonenfsm_mbuftouio(mrep, uiop, siz, dpos)
279234370Sjasone	struct mbuf **mrep;
280234370Sjasone	register struct uio *uiop;
281234370Sjasone	int siz;
282234370Sjasone	caddr_t *dpos;
283234370Sjasone{
284234370Sjasone	register char *mbufcp, *uiocp;
285234370Sjasone	register int xfer, left, len;
286234370Sjasone	register struct mbuf *mp;
287234370Sjasone	long uiosiz, rem;
288234370Sjasone	int error = 0;
289234370Sjasone
290234370Sjasone	mp = *mrep;
291234370Sjasone	mbufcp = *dpos;
292234370Sjasone	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
293234370Sjasone	rem = nfsm_rndup(siz)-siz;
294234370Sjasone	while (siz > 0) {
295234370Sjasone		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
296234370Sjasone			return (EFBIG);
297234370Sjasone		left = uiop->uio_iov->iov_len;
298234370Sjasone		uiocp = uiop->uio_iov->iov_base;
299234370Sjasone		if (left > siz)
300234370Sjasone			left = siz;
301234370Sjasone		uiosiz = left;
302234370Sjasone		while (left > 0) {
303234370Sjasone			while (len == 0) {
304234370Sjasone				mp = mp->m_next;
305234370Sjasone				if (mp == NULL)
306234370Sjasone					return (EBADRPC);
307234370Sjasone				mbufcp = mtod(mp, caddr_t);
308234370Sjasone				len = mp->m_len;
309234370Sjasone			}
310234370Sjasone			xfer = (left > len) ? len : left;
311234370Sjasone#ifdef notdef
312234370Sjasone			/* Not Yet.. */
313242844Sjasone			if (uiop->uio_iov->iov_op != NULL)
314242844Sjasone				(*(uiop->uio_iov->iov_op))
315242844Sjasone				(mbufcp, uiocp, xfer);
316242844Sjasone			else
317242844Sjasone#endif
318242844Sjasone			if (uiop->uio_segflg == UIO_SYSSPACE)
319242844Sjasone				bcopy(mbufcp, uiocp, xfer);
320242844Sjasone			else
321234370Sjasone				copyout(mbufcp, uiocp, xfer);
322234370Sjasone			left -= xfer;
323234370Sjasone			len -= xfer;
324234370Sjasone			mbufcp += xfer;
325234370Sjasone			uiocp += xfer;
326234370Sjasone			uiop->uio_offset += xfer;
327234370Sjasone			uiop->uio_resid -= xfer;
328234370Sjasone		}
329234370Sjasone		if (uiop->uio_iov->iov_len <= siz) {
330234370Sjasone			uiop->uio_iovcnt--;
331234370Sjasone			uiop->uio_iov++;
332234370Sjasone		} else {
333234370Sjasone			uiop->uio_iov->iov_base += uiosiz;
334234370Sjasone			uiop->uio_iov->iov_len -= uiosiz;
335234370Sjasone		}
336234370Sjasone		siz -= uiosiz;
337234370Sjasone	}
338234370Sjasone	*dpos = mbufcp;
339234370Sjasone	*mrep = mp;
340234370Sjasone	if (rem > 0) {
341234370Sjasone		if (len < rem)
342234370Sjasone			error = nfs_adv(mrep, dpos, rem, len);
343234370Sjasone		else
344234370Sjasone			*dpos += rem;
345234370Sjasone	}
346234370Sjasone	return (error);
347234370Sjasone}
348234370Sjasone
349234370Sjasone/*
350234370Sjasone * copies a uio scatter/gather list to an mbuf chain...
351234370Sjasone */
352234370Sjasoneint
353234370Sjasonenfsm_uiotombuf(uiop, mq, siz, bpos)
354234370Sjasone	register struct uio *uiop;
355234370Sjasone	struct mbuf **mq;
356234370Sjasone	int siz;
357234370Sjasone	caddr_t *bpos;
358234370Sjasone{
359234370Sjasone	register char *uiocp;
360234370Sjasone	register struct mbuf *mp, *mp2;
361234370Sjasone	register int xfer, left, mlen;
362234370Sjasone	int uiosiz, clflg, rem;
363234370Sjasone	char *cp;
364234370Sjasone
365234370Sjasone	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
366234370Sjasone		clflg = 1;
367234370Sjasone	else
368234370Sjasone		clflg = 0;
369234370Sjasone	rem = nfsm_rndup(siz)-siz;
370234370Sjasone	mp = mp2 = *mq;
371234370Sjasone	while (siz > 0) {
372234370Sjasone		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
373234370Sjasone			return (EINVAL);
374234370Sjasone		left = uiop->uio_iov->iov_len;
375234370Sjasone		uiocp = uiop->uio_iov->iov_base;
376234370Sjasone		if (left > siz)
377234370Sjasone			left = siz;
378234370Sjasone		uiosiz = left;
379234370Sjasone		while (left > 0) {
380234370Sjasone			mlen = M_TRAILINGSPACE(mp);
381234370Sjasone			if (mlen == 0) {
382234370Sjasone				MGET(mp, M_WAIT, MT_DATA);
383234370Sjasone				if (clflg)
384234370Sjasone					MCLGET(mp, M_WAIT);
385234370Sjasone				mp->m_len = 0;
386234370Sjasone				mp2->m_next = mp;
387234370Sjasone				mp2 = mp;
388234370Sjasone				mlen = M_TRAILINGSPACE(mp);
389234370Sjasone			}
390234370Sjasone			xfer = (left > mlen) ? mlen : left;
391234370Sjasone#ifdef notdef
392234370Sjasone			/* Not Yet.. */
393234370Sjasone			if (uiop->uio_iov->iov_op != NULL)
394234370Sjasone				(*(uiop->uio_iov->iov_op))
395251300Sjasone				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
396251300Sjasone			else
397251300Sjasone#endif
398251300Sjasone			if (uiop->uio_segflg == UIO_SYSSPACE)
399251300Sjasone				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
400251300Sjasone			else
401251300Sjasone				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
402251300Sjasone			mp->m_len += xfer;
403251300Sjasone			left -= xfer;
404251300Sjasone			uiocp += xfer;
405251300Sjasone			uiop->uio_offset += xfer;
406251300Sjasone			uiop->uio_resid -= xfer;
407251300Sjasone		}
408234370Sjasone		if (uiop->uio_iov->iov_len <= siz) {
409234370Sjasone			uiop->uio_iovcnt--;
410234370Sjasone			uiop->uio_iov++;
411234370Sjasone		} else {
412234370Sjasone			uiop->uio_iov->iov_base += uiosiz;
413234370Sjasone			uiop->uio_iov->iov_len -= uiosiz;
414234370Sjasone		}
415234370Sjasone		siz -= uiosiz;
416234370Sjasone	}
417234370Sjasone	if (rem > 0) {
418234370Sjasone		if (rem > M_TRAILINGSPACE(mp)) {
419234370Sjasone			MGET(mp, M_WAIT, MT_DATA);
420234370Sjasone			mp->m_len = 0;
421234370Sjasone			mp2->m_next = mp;
422234370Sjasone		}
423234370Sjasone		cp = mtod(mp, caddr_t)+mp->m_len;
424234370Sjasone		for (left = 0; left < rem; left++)
425234370Sjasone			*cp++ = '\0';
426234370Sjasone		mp->m_len += rem;
427234569Sjasone		*bpos = cp;
428234370Sjasone	} else
429234569Sjasone		*bpos = mtod(mp, caddr_t)+mp->m_len;
430234370Sjasone	*mq = mp;
431234370Sjasone	return (0);
432234370Sjasone}
433234370Sjasone
434234370Sjasone/*
435234370Sjasone * Help break down an mbuf chain by setting the first siz bytes contiguous
436234370Sjasone * pointed to by returned val.
437234370Sjasone * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
438234370Sjasone * cases. (The macros use the vars. dpos and dpos2)
439234370Sjasone */
440234370Sjasoneint
441234370Sjasonenfsm_disct(mdp, dposp, siz, left, cp2)
442234370Sjasone	struct mbuf **mdp;
443234370Sjasone	caddr_t *dposp;
444234370Sjasone	int siz;
445234370Sjasone	int left;
446234370Sjasone	caddr_t *cp2;
447234370Sjasone{
448234370Sjasone	register struct mbuf *mp, *mp2;
449234370Sjasone	register int siz2, xfer;
450234370Sjasone	register caddr_t p;
451234370Sjasone
452234370Sjasone	mp = *mdp;
453234370Sjasone	while (left == 0) {
454234370Sjasone		*mdp = mp = mp->m_next;
455234370Sjasone		if (mp == NULL)
456234370Sjasone			return (EBADRPC);
457234370Sjasone		left = mp->m_len;
458234370Sjasone		*dposp = mtod(mp, caddr_t);
459234370Sjasone	}
460234370Sjasone	if (left >= siz) {
461234370Sjasone		*cp2 = *dposp;
462234370Sjasone		*dposp += siz;
463234370Sjasone	} else if (mp->m_next == NULL) {
464234370Sjasone		return (EBADRPC);
465234370Sjasone	} else if (siz > MHLEN) {
466234370Sjasone		panic("nfs S too big");
467234370Sjasone	} else {
468234370Sjasone		MGET(mp2, M_WAIT, MT_DATA);
469234370Sjasone		mp2->m_next = mp->m_next;
470234370Sjasone		mp->m_next = mp2;
471234370Sjasone		mp->m_len -= left;
472234370Sjasone		mp = mp2;
473234370Sjasone		*cp2 = p = mtod(mp, caddr_t);
474234370Sjasone		bcopy(*dposp, p, left);		/* Copy what was left */
475234370Sjasone		siz2 = siz-left;
476234370Sjasone		p += left;
477234370Sjasone		mp2 = mp->m_next;
478234370Sjasone		/* Loop around copying up the siz2 bytes */
479234370Sjasone		while (siz2 > 0) {
480234370Sjasone			if (mp2 == NULL)
481234370Sjasone				return (EBADRPC);
482234370Sjasone			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
483234370Sjasone			if (xfer > 0) {
484234370Sjasone				bcopy(mtod(mp2, caddr_t), p, xfer);
485234370Sjasone				NFSMADV(mp2, xfer);
486234370Sjasone				mp2->m_len -= xfer;
487234370Sjasone				p += xfer;
488234370Sjasone				siz2 -= xfer;
489234370Sjasone			}
490234370Sjasone			if (siz2 > 0)
491234370Sjasone				mp2 = mp2->m_next;
492234370Sjasone		}
493234370Sjasone		mp->m_len = siz;
494234370Sjasone		*mdp = mp2;
495234370Sjasone		*dposp = mtod(mp2, caddr_t);
496234370Sjasone	}
497234370Sjasone	return (0);
498234370Sjasone}
499234370Sjasone
500234370Sjasone/*
501234370Sjasone * Advance the position in the mbuf chain.
502234370Sjasone */
503234370Sjasoneint
504234370Sjasonenfs_adv(mdp, dposp, offs, left)
505234370Sjasone	struct mbuf **mdp;
506234370Sjasone	caddr_t *dposp;
507234370Sjasone	int offs;
508234370Sjasone	int left;
509234370Sjasone{
510234370Sjasone	register struct mbuf *m;
511234370Sjasone	register int s;
512234370Sjasone
513234370Sjasone	m = *mdp;
514234370Sjasone	s = left;
515234370Sjasone	while (s < offs) {
516234370Sjasone		offs -= s;
517234370Sjasone		m = m->m_next;
518234370Sjasone		if (m == NULL)
519234370Sjasone			return (EBADRPC);
520234370Sjasone		s = m->m_len;
521234370Sjasone	}
522234370Sjasone	*mdp = m;
523234370Sjasone	*dposp = mtod(m, caddr_t)+offs;
524234370Sjasone	return (0);
525234370Sjasone}
526234370Sjasone
527234370Sjasone/*
528234370Sjasone * Copy a string into mbufs for the hard cases...
529234370Sjasone */
530234370Sjasoneint
531234370Sjasonenfsm_strtmbuf(mb, bpos, cp, siz)
532234370Sjasone	struct mbuf **mb;
533234370Sjasone	char **bpos;
534234370Sjasone	char *cp;
535234370Sjasone	long siz;
536234370Sjasone{
537234370Sjasone	register struct mbuf *m1 = 0, *m2;
538234370Sjasone	long left, xfer, len, tlen;
539234370Sjasone	u_long *tl;
540234370Sjasone	int putsize;
541234370Sjasone
542234370Sjasone	putsize = 1;
543234370Sjasone	m2 = *mb;
544234370Sjasone	left = M_TRAILINGSPACE(m2);
545234370Sjasone	if (left > 0) {
546234370Sjasone		tl = ((u_long *)(*bpos));
547234370Sjasone		*tl++ = txdr_unsigned(siz);
548234370Sjasone		putsize = 0;
549234370Sjasone		left -= NFSX_UNSIGNED;
550234370Sjasone		m2->m_len += NFSX_UNSIGNED;
551234370Sjasone		if (left > 0) {
552234370Sjasone			bcopy(cp, (caddr_t) tl, left);
553234370Sjasone			siz -= left;
554234370Sjasone			cp += left;
555234370Sjasone			m2->m_len += left;
556234370Sjasone			left = 0;
557234370Sjasone		}
558234370Sjasone	}
559234370Sjasone	/* Loop around adding mbufs */
560234370Sjasone	while (siz > 0) {
561234370Sjasone		MGET(m1, M_WAIT, MT_DATA);
562234370Sjasone		if (siz > MLEN)
563234370Sjasone			MCLGET(m1, M_WAIT);
564234370Sjasone		m1->m_len = NFSMSIZ(m1);
565234370Sjasone		m2->m_next = m1;
566234370Sjasone		m2 = m1;
567234370Sjasone		tl = mtod(m1, u_long *);
568234370Sjasone		tlen = 0;
569234370Sjasone		if (putsize) {
570234370Sjasone			*tl++ = txdr_unsigned(siz);
571234370Sjasone			m1->m_len -= NFSX_UNSIGNED;
572234370Sjasone			tlen = NFSX_UNSIGNED;
573234370Sjasone			putsize = 0;
574234370Sjasone		}
575234370Sjasone		if (siz < m1->m_len) {
576234370Sjasone			len = nfsm_rndup(siz);
577234370Sjasone			xfer = siz;
578234370Sjasone			if (xfer < len)
579234370Sjasone				*(tl+(xfer>>2)) = 0;
580234370Sjasone		} else {
581234370Sjasone			xfer = len = m1->m_len;
582234370Sjasone		}
583234370Sjasone		bcopy(cp, (caddr_t) tl, xfer);
584234370Sjasone		m1->m_len = len+tlen;
585234370Sjasone		siz -= xfer;
586234370Sjasone		cp += xfer;
587234370Sjasone	}
588234370Sjasone	*mb = m1;
589234370Sjasone	*bpos = mtod(m1, caddr_t)+m1->m_len;
590235238Sjasone	return (0);
591235238Sjasone}
592235238Sjasone
593235238Sjasone/*
594235238Sjasone * Called once to initialize data structures...
595235238Sjasone */
596234370Sjasoneint
597234370Sjasonenfs_init()
598234370Sjasone{
599234370Sjasone	register int i;
600234370Sjasone
601234370Sjasone	nfsrtt.pos = 0;
602234370Sjasone	rpc_vers = txdr_unsigned(RPC_VER2);
603234370Sjasone	rpc_call = txdr_unsigned(RPC_CALL);
604234370Sjasone	rpc_reply = txdr_unsigned(RPC_REPLY);
605234370Sjasone	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
606234370Sjasone	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
607234370Sjasone	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
608234370Sjasone	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
609234370Sjasone	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
610234370Sjasone	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
611234370Sjasone	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
612234370Sjasone	nfs_vers = txdr_unsigned(NFS_VER2);
613234370Sjasone	nfs_prog = txdr_unsigned(NFS_PROG);
614234370Sjasone	nfs_true = txdr_unsigned(TRUE);
615234370Sjasone	nfs_false = txdr_unsigned(FALSE);
616234370Sjasone	/* Loop thru nfs procids */
617234370Sjasone	for (i = 0; i < NFS_NPROCS; i++)
618234370Sjasone		nfs_procids[i] = txdr_unsigned(i);
619234370Sjasone	/* Ensure async daemons disabled */
620234370Sjasone	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
621234370Sjasone		nfs_iodwant[i] = (struct proc *)0;
622234370Sjasone	TAILQ_INIT(&nfs_bufq);
623234370Sjasone	nfs_xdrneg1 = txdr_unsigned(-1);
624234370Sjasone	nfs_nhinit();			/* Init the nfsnode table */
625234370Sjasone	nfsrv_init(0);			/* Init server data structures */
626234370Sjasone	nfsrv_initcache();		/* Init the server request cache */
627234370Sjasone
628234370Sjasone	/*
629234370Sjasone	 * Initialize the nqnfs server stuff.
630234370Sjasone	 */
631234370Sjasone	if (nqnfsstarttime == 0) {
632234370Sjasone		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
633234370Sjasone			+ nqsrv_clockskew + nqsrv_writeslack;
634234370Sjasone		NQLOADNOVRAM(nqnfsstarttime);
635234370Sjasone		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
636234370Sjasone		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
637234370Sjasone		nqthead.th_head[0] = &nqthead;
638234370Sjasone		nqthead.th_head[1] = &nqthead;
639234370Sjasone		nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash);
640234370Sjasone	}
641234370Sjasone
642234370Sjasone	/*
643234370Sjasone	 * Initialize reply list and start timer
644234370Sjasone	 */
645234370Sjasone	nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
646234370Sjasone	nfs_timer();
647234370Sjasone
648234370Sjasone	/*
649234370Sjasone	 * Set up lease_check and lease_updatetime so that other parts
650234370Sjasone	 * of the system can call us, if we are loadable.
651234370Sjasone	 */
652234370Sjasone	lease_check = nfs_lease_check;
653234370Sjasone	lease_updatetime = nfs_lease_updatetime;
654234370Sjasone	vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
655234370Sjasone#ifdef VFS_LKM
656234370Sjasone	sysent[SYS_nfssvc].sy_narg = 2;
657234370Sjasone	sysent[SYS_nfssvc].sy_call = nfssvc;
658234370Sjasone	sysent[SYS_getfh].sy_narg = 2;
659234370Sjasone	sysent[SYS_getfh].sy_call = getfh;
660234370Sjasone#endif
661234370Sjasone
662234370Sjasone	return (0);
663234370Sjasone}
664234370Sjasone
665234370Sjasone/*
666234370Sjasone * Attribute cache routines.
667245868Sjasone * nfs_loadattrcache() - loads or updates the cache contents from attributes
668234370Sjasone *	that are on the mbuf list
669234370Sjasone * nfs_getattrcache() - returns valid attributes if found in cache, returns
670242844Sjasone *	error otherwise
671242844Sjasone */
672242844Sjasone
673242844Sjasone/*
674242844Sjasone * Load the attribute cache (that lives in the nfsnode entry) with
675242844Sjasone * the values on the mbuf list and
676242844Sjasone * Iff vap not NULL
677234370Sjasone *    copy the attributes to *vaper
678234370Sjasone */
679242844Sjasoneint
680234370Sjasonenfs_loadattrcache(vpp, mdp, dposp, vaper)
681234370Sjasone	struct vnode **vpp;
682234370Sjasone	struct mbuf **mdp;
683234370Sjasone	caddr_t *dposp;
684234370Sjasone	struct vattr *vaper;
685234370Sjasone{
686242844Sjasone	register struct vnode *vp = *vpp;
687234370Sjasone	register struct vattr *vap;
688234370Sjasone	register struct nfsv2_fattr *fp;
689234370Sjasone	extern int (**spec_nfsv2nodeop_p)();
690234370Sjasone	register struct nfsnode *np, *nq, **nhpp;
691234370Sjasone	register long t1;
692234370Sjasone	caddr_t dpos, cp2;
693234370Sjasone	int error = 0, isnq;
694234370Sjasone	struct mbuf *md;
695234370Sjasone	enum vtype vtyp;
696234370Sjasone	u_short vmode;
697234370Sjasone	long rdev;
698234370Sjasone	struct timespec mtime;
699234370Sjasone	struct vnode *nvp;
700234370Sjasone
701234370Sjasone	md = *mdp;
702234370Sjasone	dpos = *dposp;
703234370Sjasone	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
704234370Sjasone	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
705234370Sjasone	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2))
706242844Sjasone		return (error);
707242844Sjasone	fp = (struct nfsv2_fattr *)cp2;
708234370Sjasone	vtyp = nfstov_type(fp->fa_type);
709234370Sjasone	vmode = fxdr_unsigned(u_short, fp->fa_mode);
710234370Sjasone	if (vtyp == VNON || vtyp == VREG)
711234370Sjasone		vtyp = IFTOVT(vmode);
712234370Sjasone	if (isnq) {
713234370Sjasone		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
714234370Sjasone		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
715242844Sjasone	} else {
716234370Sjasone		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
717234370Sjasone		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
718234370Sjasone	}
719234370Sjasone	/*
720234370Sjasone	 * If v_type == VNON it is a new node, so fill in the v_type,
721234370Sjasone	 * n_mtime fields. Check to see if it represents a special
722234370Sjasone	 * device, and if so, check for a possible alias. Once the
723242844Sjasone	 * correct vnode has been obtained, fill in the rest of the
724234370Sjasone	 * information.
725234370Sjasone	 */
726234370Sjasone	np = VTONFS(vp);
727234370Sjasone	if (vp->v_type == VNON) {
728234370Sjasone		if (vtyp == VCHR && rdev == 0xffffffff)
729234370Sjasone			vp->v_type = vtyp = VFIFO;
730234370Sjasone		else
731234370Sjasone			vp->v_type = vtyp;
732234370Sjasone		if (vp->v_type == VFIFO) {
733234370Sjasone			extern int (**fifo_nfsv2nodeop_p)();
734234370Sjasone			vp->v_op = fifo_nfsv2nodeop_p;
735234370Sjasone		}
736234370Sjasone		if (vp->v_type == VCHR || vp->v_type == VBLK) {
737234370Sjasone			vp->v_op = spec_nfsv2nodeop_p;
738234370Sjasone			if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
739234370Sjasone				/*
740234370Sjasone				 * Discard unneeded vnode, but save its nfsnode.
741234370Sjasone				 */
742234370Sjasone				if (nq = np->n_forw)
743234370Sjasone					nq->n_back = np->n_back;
744234370Sjasone				*np->n_back = nq;
745242844Sjasone				nvp->v_data = vp->v_data;
746234370Sjasone				vp->v_data = NULL;
747234370Sjasone				vp->v_op = spec_vnodeop_p;
748234370Sjasone				vrele(vp);
749234370Sjasone				vgone(vp);
750234370Sjasone				/*
751234370Sjasone				 * Reinitialize aliased node.
752234370Sjasone				 */
753234370Sjasone				np->n_vnode = nvp;
754234370Sjasone				nhpp = (struct nfsnode **)nfs_hash(&np->n_fh);
755234370Sjasone				if (nq = *nhpp)
756234370Sjasone					nq->n_back = &np->n_forw;
757234370Sjasone				np->n_forw = nq;
758234370Sjasone				np->n_back = nhpp;
759234370Sjasone				*nhpp = np;
760234370Sjasone				*vpp = vp = nvp;
761234370Sjasone			}
762234370Sjasone		}
763234370Sjasone		np->n_mtime = mtime.ts_sec;
764234370Sjasone	}
765234370Sjasone	vap = &np->n_vattr;
766234370Sjasone	vap->va_type = vtyp;
767234370Sjasone	vap->va_mode = (vmode & 07777);
768234370Sjasone	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
769234370Sjasone	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
770234370Sjasone	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
771234370Sjasone	vap->va_rdev = (dev_t)rdev;
772242844Sjasone	vap->va_mtime = mtime;
773242844Sjasone	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
774234370Sjasone	if (isnq) {
775234370Sjasone		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
776234370Sjasone		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
777234370Sjasone		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
778234370Sjasone		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
779234370Sjasone		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
780234370Sjasone		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
781234370Sjasone		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
782234370Sjasone		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
783234543Sjasone		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
784234370Sjasone	} else {
785234370Sjasone		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
786234370Sjasone		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
787234370Sjasone		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
788234370Sjasone		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
789234370Sjasone		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
790234370Sjasone		vap->va_flags = 0;
791234543Sjasone		vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec);
792234370Sjasone		vap->va_ctime.ts_nsec = 0;
793234543Sjasone		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec);
794234543Sjasone		vap->va_filerev = 0;
795234543Sjasone	}
796234370Sjasone	if (vap->va_size != np->n_size) {
797234370Sjasone		if (vap->va_type == VREG) {
798234543Sjasone			if (np->n_flag & NMODIFIED) {
799234370Sjasone				if (vap->va_size < np->n_size)
800234370Sjasone					vap->va_size = np->n_size;
801234370Sjasone				else
802234370Sjasone					np->n_size = vap->va_size;
803234370Sjasone			} else
804234370Sjasone				np->n_size = vap->va_size;
805234370Sjasone			vnode_pager_setsize(vp, (u_long)np->n_size);
806234370Sjasone		} else
807234370Sjasone			np->n_size = vap->va_size;
808234370Sjasone	}
809234370Sjasone	np->n_attrstamp = time.tv_sec;
810234370Sjasone	*dposp = dpos;
811234370Sjasone	*mdp = md;
812234370Sjasone	if (vaper != NULL) {
813234370Sjasone		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
814234370Sjasone#ifdef notdef
815234370Sjasone		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
816234370Sjasone		if (np->n_size > vap->va_size)
817234370Sjasone			vaper->va_size = np->n_size;
818234543Sjasone#endif
819234370Sjasone		if (np->n_flag & NCHG) {
820234370Sjasone			if (np->n_flag & NACC) {
821234370Sjasone				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
822234370Sjasone				vaper->va_atime.ts_nsec =
823234543Sjasone				    np->n_atim.tv_usec * 1000;
824234370Sjasone			}
825234370Sjasone			if (np->n_flag & NUPD) {
826234370Sjasone				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
827234370Sjasone				vaper->va_mtime.ts_nsec =
828234370Sjasone				    np->n_mtim.tv_usec * 1000;
829234370Sjasone			}
830234370Sjasone		}
831234370Sjasone	}
832234370Sjasone	return (0);
833234370Sjasone}
834234370Sjasone
835234370Sjasone/*
836234370Sjasone * Check the time stamp
837234370Sjasone * If the cache is valid, copy contents to *vap and return 0
838234370Sjasone * otherwise return an error
839234370Sjasone */
840234370Sjasoneint
841234370Sjasonenfs_getattrcache(vp, vaper)
842234370Sjasone	register struct vnode *vp;
843234370Sjasone	struct vattr *vaper;
844234370Sjasone{
845234370Sjasone	register struct nfsnode *np = VTONFS(vp);
846234543Sjasone	register struct vattr *vap;
847234543Sjasone
848234543Sjasone	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
849234543Sjasone		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
850234543Sjasone			nfsstats.attrcache_misses++;
851234543Sjasone			return (ENOENT);
852234543Sjasone		}
853234543Sjasone	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
854234543Sjasone		nfsstats.attrcache_misses++;
855234543Sjasone		return (ENOENT);
856234543Sjasone	}
857234543Sjasone	nfsstats.attrcache_hits++;
858234370Sjasone	vap = &np->n_vattr;
859234370Sjasone	if (vap->va_size != np->n_size) {
860234370Sjasone		if (vap->va_type == VREG) {
861234370Sjasone			if (np->n_flag & NMODIFIED) {
862234370Sjasone				if (vap->va_size < np->n_size)
863234370Sjasone					vap->va_size = np->n_size;
864234370Sjasone				else
865234370Sjasone					np->n_size = vap->va_size;
866234370Sjasone			} else
867234370Sjasone				np->n_size = vap->va_size;
868234370Sjasone			vnode_pager_setsize(vp, (u_long)np->n_size);
869242844Sjasone		} else
870234370Sjasone			np->n_size = vap->va_size;
871234370Sjasone	}
872234370Sjasone	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
873234370Sjasone#ifdef notdef
874234370Sjasone	if ((np->n_flag & NMODIFIED) == 0) {
875234370Sjasone		np->n_size = vaper->va_size;
876234370Sjasone		vnode_pager_setsize(vp, (u_long)np->n_size);
877234370Sjasone	} else if (np->n_size > vaper->va_size)
878234370Sjasone	if (np->n_size > vaper->va_size)
879234370Sjasone		vaper->va_size = np->n_size;
880234370Sjasone#endif
881234370Sjasone	if (np->n_flag & NCHG) {
882234370Sjasone		if (np->n_flag & NACC) {
883234370Sjasone			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
884234370Sjasone			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
885234370Sjasone		}
886234370Sjasone		if (np->n_flag & NUPD) {
887234370Sjasone			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
888234370Sjasone			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
889234370Sjasone		}
890234370Sjasone	}
891234370Sjasone	return (0);
892234370Sjasone}
893234370Sjasone
894234370Sjasone/*
895234370Sjasone * Set up nameidata for a lookup() call and do it
896234370Sjasone */
897234370Sjasoneint
898234370Sjasonenfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
899234370Sjasone	register struct nameidata *ndp;
900234370Sjasone	fhandle_t *fhp;
901234370Sjasone	int len;
902234370Sjasone	struct nfssvc_sock *slp;
903234370Sjasone	struct mbuf *nam;
904234370Sjasone	struct mbuf **mdp;
905234370Sjasone	caddr_t *dposp;
906234370Sjasone	struct proc *p;
907234370Sjasone{
908234370Sjasone	register int i, rem;
909234370Sjasone	register struct mbuf *md;
910234370Sjasone	register char *fromcp, *tocp;
911234370Sjasone	struct vnode *dp;
912234370Sjasone	int error, rdonly;
913242844Sjasone	struct componentname *cnp = &ndp->ni_cnd;
914242844Sjasone
915242844Sjasone	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
916242844Sjasone	/*
917242844Sjasone	 * Copy the name from the mbuf list to ndp->ni_pnbuf
918242844Sjasone	 * and set the various ndp fields appropriately.
919242844Sjasone	 */
920242844Sjasone	fromcp = *dposp;
921242844Sjasone	tocp = cnp->cn_pnbuf;
922242844Sjasone	md = *mdp;
923242844Sjasone	rem = mtod(md, caddr_t) + md->m_len - fromcp;
924242844Sjasone	cnp->cn_hash = 0;
925242844Sjasone	for (i = 0; i < len; i++) {
926242844Sjasone		while (rem == 0) {
927234370Sjasone			md = md->m_next;
928234370Sjasone			if (md == NULL) {
929242844Sjasone				error = EBADRPC;
930234370Sjasone				goto out;
931234370Sjasone			}
932234370Sjasone			fromcp = mtod(md, caddr_t);
933234370Sjasone			rem = md->m_len;
934234370Sjasone		}
935234370Sjasone		if (*fromcp == '\0' || *fromcp == '/') {
936234370Sjasone			error = EINVAL;
937234370Sjasone			goto out;
938234370Sjasone		}
939234370Sjasone		cnp->cn_hash += (unsigned char)*fromcp;
940234370Sjasone		*tocp++ = *fromcp++;
941234370Sjasone		rem--;
942234370Sjasone	}
943234370Sjasone	*tocp = '\0';
944234370Sjasone	*mdp = md;
945234370Sjasone	*dposp = fromcp;
946234370Sjasone	len = nfsm_rndup(len)-len;
947234370Sjasone	if (len > 0) {
948234370Sjasone		if (rem >= len)
949234370Sjasone			*dposp += len;
950234370Sjasone		else if (error = nfs_adv(mdp, dposp, len, rem))
951234370Sjasone			goto out;
952234370Sjasone	}
953234370Sjasone	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
954234370Sjasone	cnp->cn_nameptr = cnp->cn_pnbuf;
955234370Sjasone	/*
956234370Sjasone	 * Extract and set starting directory.
957234370Sjasone	 */
958234370Sjasone	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
959234370Sjasone	    nam, &rdonly))
960234370Sjasone		goto out;
961234370Sjasone	if (dp->v_type != VDIR) {
962234370Sjasone		vrele(dp);
963234370Sjasone		error = ENOTDIR;
964234370Sjasone		goto out;
965234370Sjasone	}
966234370Sjasone	ndp->ni_startdir = dp;
967234370Sjasone	if (rdonly)
968234370Sjasone		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
969234370Sjasone	else
970234370Sjasone		cnp->cn_flags |= NOCROSSMOUNT;
971234370Sjasone	/*
972234370Sjasone	 * And call lookup() to do the real work
973234370Sjasone	 */
974234370Sjasone	cnp->cn_proc = p;
975234370Sjasone	if (error = lookup(ndp))
976234370Sjasone		goto out;
977234370Sjasone	/*
978234370Sjasone	 * Check for encountering a symbolic link
979234370Sjasone	 */
980234370Sjasone	if (cnp->cn_flags & ISSYMLINK) {
981234370Sjasone		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
982234370Sjasone			vput(ndp->ni_dvp);
983234370Sjasone		else
984234370Sjasone			vrele(ndp->ni_dvp);
985234370Sjasone		vput(ndp->ni_vp);
986234370Sjasone		ndp->ni_vp = NULL;
987234370Sjasone		error = EINVAL;
988234370Sjasone		goto out;
989234370Sjasone	}
990234370Sjasone	/*
991234370Sjasone	 * Check for saved name request
992234370Sjasone	 */
993234370Sjasone	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
994242844Sjasone		cnp->cn_flags |= HASBUF;
995242844Sjasone		return (0);
996242844Sjasone	}
997242844Sjasoneout:
998242844Sjasone	FREE(cnp->cn_pnbuf, M_NAMEI);
999234370Sjasone	return (error);
1000234370Sjasone}
1001234370Sjasone
1002234370Sjasone/*
1003234370Sjasone * A fiddled version of m_adj() that ensures null fill to a long
1004234370Sjasone * boundary and only trims off the back end
1005234370Sjasone */
1006234370Sjasonevoid
1007234370Sjasonenfsm_adj(mp, len, nul)
1008234370Sjasone	struct mbuf *mp;
1009234370Sjasone	register int len;
1010234370Sjasone	int nul;
1011234370Sjasone{
1012234370Sjasone	register struct mbuf *m;
1013234370Sjasone	register int count, i;
1014234370Sjasone	register char *cp;
1015234370Sjasone
1016234370Sjasone	/*
1017234370Sjasone	 * Trim from tail.  Scan the mbuf chain,
1018234370Sjasone	 * calculating its length and finding the last mbuf.
1019234370Sjasone	 * If the adjustment only affects this mbuf, then just
1020234370Sjasone	 * adjust and return.  Otherwise, rescan and truncate
1021234370Sjasone	 * after the remaining size.
1022234370Sjasone	 */
1023234370Sjasone	count = 0;
1024234370Sjasone	m = mp;
1025234370Sjasone	for (;;) {
1026234370Sjasone		count += m->m_len;
1027234370Sjasone		if (m->m_next == (struct mbuf *)0)
1028234370Sjasone			break;
1029234370Sjasone		m = m->m_next;
1030234370Sjasone	}
1031234370Sjasone	if (m->m_len > len) {
1032234370Sjasone		m->m_len -= len;
1033234370Sjasone		if (nul > 0) {
1034234370Sjasone			cp = mtod(m, caddr_t)+m->m_len-nul;
1035234370Sjasone			for (i = 0; i < nul; i++)
1036234370Sjasone				*cp++ = '\0';
1037234370Sjasone		}
1038242844Sjasone		return;
1039242844Sjasone	}
1040242844Sjasone	count -= len;
1041234370Sjasone	if (count < 0)
1042234370Sjasone		count = 0;
1043234370Sjasone	/*
1044234370Sjasone	 * Correct length for chain is "count".
1045234370Sjasone	 * Find the mbuf with last data, adjust its length,
1046235322Sjasone	 * and toss data from remaining mbufs on chain.
1047234370Sjasone	 */
1048234370Sjasone	for (m = mp; m; m = m->m_next) {
1049234370Sjasone		if (m->m_len >= count) {
1050234370Sjasone			m->m_len = count;
1051235322Sjasone			if (nul > 0) {
1052234370Sjasone				cp = mtod(m, caddr_t)+m->m_len-nul;
1053234370Sjasone				for (i = 0; i < nul; i++)
1054234370Sjasone					*cp++ = '\0';
1055234370Sjasone			}
1056234370Sjasone			break;
1057234370Sjasone		}
1058234370Sjasone		count -= m->m_len;
1059234370Sjasone	}
1060234370Sjasone	while (m = m->m_next)
1061234370Sjasone		m->m_len = 0;
1062234370Sjasone}
1063234370Sjasone
1064234370Sjasone/*
1065234370Sjasone * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1066234370Sjasone * 	- look up fsid in mount list (if not found ret error)
1067234370Sjasone *	- get vp and export rights by calling VFS_FHTOVP()
1068234370Sjasone *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1069234370Sjasone *	- if not lockflag unlock it with VOP_UNLOCK()
1070234370Sjasone */
1071234370Sjasoneint
1072234370Sjasonenfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
1073234370Sjasone	fhandle_t *fhp;
1074234370Sjasone	int lockflag;
1075234370Sjasone	struct vnode **vpp;
1076234370Sjasone	struct ucred *cred;
1077234370Sjasone	struct nfssvc_sock *slp;
1078234370Sjasone	struct mbuf *nam;
1079242844Sjasone	int *rdonlyp;
1080242844Sjasone{
1081242844Sjasone	register struct mount *mp;
1082242844Sjasone	register struct nfsuid *uidp;
1083242844Sjasone	register int i;
1084242844Sjasone	struct ucred *credanon;
1085242844Sjasone	int error, exflags;
1086242844Sjasone
1087242844Sjasone	*vpp = (struct vnode *)0;
1088234370Sjasone	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
1089234370Sjasone		return (ESTALE);
1090234370Sjasone	if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon))
1091234370Sjasone		return (error);
1092234370Sjasone	/*
1093234370Sjasone	 * Check/setup credentials.
1094234370Sjasone	 */
1095234370Sjasone	if (exflags & MNT_EXKERB) {
1096234370Sjasone		uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
1097234370Sjasone		while (uidp) {
1098234370Sjasone			if (uidp->nu_uid == cred->cr_uid)
1099234370Sjasone				break;
1100234370Sjasone			uidp = uidp->nu_hnext;
1101234370Sjasone		}
1102234370Sjasone		if (uidp) {
1103234370Sjasone			cred->cr_uid = uidp->nu_cr.cr_uid;
1104234370Sjasone			for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
1105234370Sjasone				cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
1106234370Sjasone		} else {
1107234370Sjasone			vput(*vpp);
1108234370Sjasone			return (NQNFS_AUTHERR);
1109234370Sjasone		}
1110234370Sjasone	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1111234370Sjasone		cred->cr_uid = credanon->cr_uid;
1112234370Sjasone		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1113234370Sjasone			cred->cr_groups[i] = credanon->cr_groups[i];
1114234370Sjasone	}
1115234370Sjasone	if (exflags & MNT_EXRDONLY)
1116234370Sjasone		*rdonlyp = 1;
1117234370Sjasone	else
1118234370Sjasone		*rdonlyp = 0;
1119234370Sjasone	if (!lockflag)
1120234370Sjasone		VOP_UNLOCK(*vpp);
1121234370Sjasone	return (0);
1122234370Sjasone}
1123234370Sjasone
1124234370Sjasone/*
1125234370Sjasone * This function compares two net addresses by family and returns TRUE
1126234370Sjasone * if they are the same host.
1127234370Sjasone * If there is any doubt, return FALSE.
1128234370Sjasone * The AF_INET family is handled as a special case so that address mbufs
1129234370Sjasone * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1130234370Sjasone */
1131234370Sjasoneint
1132234370Sjasonenetaddr_match(family, haddr, nam)
1133234370Sjasone	int family;
1134234370Sjasone	union nethostaddr *haddr;
1135234370Sjasone	struct mbuf *nam;
1136234370Sjasone{
1137234370Sjasone	register struct sockaddr_in *inetaddr;
1138234370Sjasone
1139234370Sjasone	switch (family) {
1140234370Sjasone	case AF_INET:
1141234370Sjasone		inetaddr = mtod(nam, struct sockaddr_in *);
1142234370Sjasone		if (inetaddr->sin_family == AF_INET &&
1143234370Sjasone		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1144234370Sjasone			return (1);
1145234370Sjasone		break;
1146234370Sjasone#ifdef ISO
1147234370Sjasone	case AF_ISO:
1148234370Sjasone	    {
1149234370Sjasone		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1150234370Sjasone
1151234370Sjasone		isoaddr1 = mtod(nam, struct sockaddr_iso *);
1152234370Sjasone		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1153234370Sjasone		if (isoaddr1->siso_family == AF_ISO &&
1154234370Sjasone		    isoaddr1->siso_nlen > 0 &&
1155234370Sjasone		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1156234370Sjasone		    SAME_ISOADDR(isoaddr1, isoaddr2))
1157234370Sjasone			return (1);
1158234370Sjasone		break;
1159234370Sjasone	    }
1160234370Sjasone#endif	/* ISO */
1161234370Sjasone	default:
1162234370Sjasone		break;
1163234370Sjasone	};
1164234370Sjasone	return (0);
1165234370Sjasone}
1166234370Sjasone