nfs_srvsubs.c revision 2979
1192067Snwhitehorn/*
2192067Snwhitehorn * Copyright (c) 1989, 1993
3192067Snwhitehorn *	The Regents of the University of California.  All rights reserved.
4192067Snwhitehorn *
5192067Snwhitehorn * This code is derived from software contributed to Berkeley by
6192067Snwhitehorn * Rick Macklem at The University of Guelph.
7192067Snwhitehorn *
8192067Snwhitehorn * Redistribution and use in source and binary forms, with or without
9192067Snwhitehorn * modification, are permitted provided that the following conditions
10192067Snwhitehorn * are met:
11192067Snwhitehorn * 1. Redistributions of source code must retain the above copyright
12192067Snwhitehorn *    notice, this list of conditions and the following disclaimer.
13192067Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
14192067Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
15192067Snwhitehorn *    documentation and/or other materials provided with the distribution.
16192067Snwhitehorn * 3. All advertising materials mentioning features or use of this software
17192067Snwhitehorn *    must display the following acknowledgement:
18192067Snwhitehorn *	This product includes software developed by the University of
19192067Snwhitehorn *	California, Berkeley and its contributors.
20192067Snwhitehorn * 4. Neither the name of the University nor the names of its contributors
21192067Snwhitehorn *    may be used to endorse or promote products derived from this software
22192067Snwhitehorn *    without specific prior written permission.
23192067Snwhitehorn *
24192067Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25192067Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26192067Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27192067Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28192067Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29192067Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30192067Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31192067Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32192067Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33192067Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34192067Snwhitehorn * SUCH DAMAGE.
35192067Snwhitehorn *
36192067Snwhitehorn *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
37192067Snwhitehorn * $Id: nfs_subs.c,v 1.3 1994/08/02 07:52:13 davidg Exp $
38192067Snwhitehorn */
39192067Snwhitehorn
40192067Snwhitehorn/*
41192067Snwhitehorn * These functions support the macros and help fiddle mbuf chains for
42192067Snwhitehorn * the nfs op functions. They do things like create the rpc header and
43192067Snwhitehorn * copy data between mbuf chains and uio lists.
44192067Snwhitehorn */
45192067Snwhitehorn#include <sys/param.h>
46192067Snwhitehorn#include <sys/proc.h>
47192067Snwhitehorn#include <sys/systm.h>
48192067Snwhitehorn#include <sys/kernel.h>
49192067Snwhitehorn#include <sys/mount.h>
50192067Snwhitehorn#include <sys/vnode.h>
51192067Snwhitehorn#include <sys/namei.h>
52192067Snwhitehorn#include <sys/mbuf.h>
53192067Snwhitehorn#include <sys/socket.h>
54192067Snwhitehorn#include <sys/stat.h>
55192067Snwhitehorn
56192067Snwhitehorn#include <nfs/rpcv2.h>
57192067Snwhitehorn#include <nfs/nfsv2.h>
58192067Snwhitehorn#include <nfs/nfsnode.h>
59192067Snwhitehorn#include <nfs/nfs.h>
60192067Snwhitehorn#include <nfs/xdr_subs.h>
61192067Snwhitehorn#include <nfs/nfsm_subs.h>
62192067Snwhitehorn#include <nfs/nfsmount.h>
63192067Snwhitehorn#include <nfs/nqnfs.h>
64192067Snwhitehorn#include <nfs/nfsrtt.h>
65192067Snwhitehorn
66192067Snwhitehorn#include <miscfs/specfs/specdev.h>
67192067Snwhitehorn
68192067Snwhitehorn#include <netinet/in.h>
69192067Snwhitehorn#ifdef ISO
70192067Snwhitehorn#include <netiso/iso.h>
71192067Snwhitehorn#endif
72192067Snwhitehorn
73192067Snwhitehorn#define TRUE	1
74192067Snwhitehorn#define	FALSE	0
75192067Snwhitehorn
76192067Snwhitehorn/*
77192067Snwhitehorn * Data items converted to xdr at startup, since they are constant
78192067Snwhitehorn * This is kinda hokey, but may save a little time doing byte swaps
79192067Snwhitehorn */
80192067Snwhitehornu_long nfs_procids[NFS_NPROCS];
81192067Snwhitehornu_long nfs_xdrneg1;
82192067Snwhitehornu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
83192067Snwhitehorn	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
84192067Snwhitehorn	rpc_auth_kerb;
85192067Snwhitehornu_long nfs_vers, nfs_prog, nfs_true, nfs_false;
86192067Snwhitehorn
87192067Snwhitehorn/* And other global data */
88192067Snwhitehornstatic u_long nfs_xid = 0;
89192067Snwhitehornenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
90192067Snwhitehornextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
91192067Snwhitehornextern struct nfsreq nfsreqh;
92192067Snwhitehornextern int nqnfs_piggy[NFS_NPROCS];
93192067Snwhitehornextern struct nfsrtt nfsrtt;
94192067Snwhitehornextern time_t nqnfsstarttime;
95192067Snwhitehornextern u_long nqnfs_prog, nqnfs_vers;
96192067Snwhitehornextern int nqsrv_clockskew;
97192067Snwhitehornextern int nqsrv_writeslack;
98192067Snwhitehornextern int nqsrv_maxlease;
99192067Snwhitehorn
100192067Snwhitehorn/*
101192067Snwhitehorn * Create the header for an rpc request packet
102192067Snwhitehorn * The hsiz is the size of the rest of the nfs request header.
103192067Snwhitehorn * (just used to decide if a cluster is a good idea)
104192067Snwhitehorn */
105192067Snwhitehornstruct mbuf *
106192067Snwhitehornnfsm_reqh(vp, procid, hsiz, bposp)
107192067Snwhitehorn	struct vnode *vp;
108192067Snwhitehorn	u_long procid;
109192067Snwhitehorn	int hsiz;
110192067Snwhitehorn	caddr_t *bposp;
111192067Snwhitehorn{
112192067Snwhitehorn	register struct mbuf *mb;
113192067Snwhitehorn	register u_long *tl;
114192067Snwhitehorn	register caddr_t bpos;
115192067Snwhitehorn	struct mbuf *mb2;
116192067Snwhitehorn	struct nfsmount *nmp;
117192067Snwhitehorn	int nqflag;
118192067Snwhitehorn
119192067Snwhitehorn	MGET(mb, M_WAIT, MT_DATA);
120192067Snwhitehorn	if (hsiz >= MINCLSIZE)
121192067Snwhitehorn		MCLGET(mb, M_WAIT);
122192067Snwhitehorn	mb->m_len = 0;
123192067Snwhitehorn	bpos = mtod(mb, caddr_t);
124192067Snwhitehorn
125192067Snwhitehorn	/*
126192067Snwhitehorn	 * For NQNFS, add lease request.
127192067Snwhitehorn	 */
128192067Snwhitehorn	if (vp) {
129192067Snwhitehorn		nmp = VFSTONFS(vp->v_mount);
130192067Snwhitehorn		if (nmp->nm_flag & NFSMNT_NQNFS) {
131192067Snwhitehorn			nqflag = NQNFS_NEEDLEASE(vp, procid);
132192067Snwhitehorn			if (nqflag) {
133192067Snwhitehorn				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
134192067Snwhitehorn				*tl++ = txdr_unsigned(nqflag);
135192067Snwhitehorn				*tl = txdr_unsigned(nmp->nm_leaseterm);
136192067Snwhitehorn			} else {
137192067Snwhitehorn				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
138192067Snwhitehorn				*tl = 0;
139192067Snwhitehorn			}
140192067Snwhitehorn		}
141192067Snwhitehorn	}
142192067Snwhitehorn	/* Finally, return values */
143192067Snwhitehorn	*bposp = bpos;
144192067Snwhitehorn	return (mb);
145192067Snwhitehorn}
146192067Snwhitehorn
147192067Snwhitehorn/*
148192067Snwhitehorn * Build the RPC header and fill in the authorization info.
149192067Snwhitehorn * The authorization string argument is only used when the credentials
150192067Snwhitehorn * come from outside of the kernel.
151192067Snwhitehorn * Returns the head of the mbuf list.
152192067Snwhitehorn */
153192067Snwhitehornstruct mbuf *
154192067Snwhitehornnfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
155192067Snwhitehorn	mrest_len, mbp, xidp)
156192067Snwhitehorn	register struct ucred *cr;
157192067Snwhitehorn	int nqnfs;
158192067Snwhitehorn	int procid;
159192067Snwhitehorn	int auth_type;
160192067Snwhitehorn	int auth_len;
161192067Snwhitehorn	char *auth_str;
162192067Snwhitehorn	struct mbuf *mrest;
163192067Snwhitehorn	int mrest_len;
164192067Snwhitehorn	struct mbuf **mbp;
165192067Snwhitehorn	u_long *xidp;
166192067Snwhitehorn{
167192067Snwhitehorn	register struct mbuf *mb;
168192067Snwhitehorn	register u_long *tl;
169192067Snwhitehorn	register caddr_t bpos;
170192067Snwhitehorn	register int i;
171192067Snwhitehorn	struct mbuf *mreq, *mb2;
172192067Snwhitehorn	int siz, grpsiz, authsiz;
173192067Snwhitehorn
174192067Snwhitehorn	authsiz = nfsm_rndup(auth_len);
175192067Snwhitehorn	if (auth_type == RPCAUTH_NQNFS)
176192067Snwhitehorn		authsiz += 2 * NFSX_UNSIGNED;
177192067Snwhitehorn	MGETHDR(mb, M_WAIT, MT_DATA);
178192067Snwhitehorn	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
179192067Snwhitehorn		MCLGET(mb, M_WAIT);
180192067Snwhitehorn	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
181192067Snwhitehorn		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
182192067Snwhitehorn	} else {
183192067Snwhitehorn		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
184192067Snwhitehorn	}
185192067Snwhitehorn	mb->m_len = 0;
186192067Snwhitehorn	mreq = mb;
187192067Snwhitehorn	bpos = mtod(mb, caddr_t);
188192067Snwhitehorn
189192067Snwhitehorn	/*
190192067Snwhitehorn	 * First the RPC header.
191192067Snwhitehorn	 */
192192067Snwhitehorn	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
193192067Snwhitehorn	if (++nfs_xid == 0)
194192067Snwhitehorn		nfs_xid++;
195192067Snwhitehorn	*tl++ = *xidp = txdr_unsigned(nfs_xid);
196192067Snwhitehorn	*tl++ = rpc_call;
197192067Snwhitehorn	*tl++ = rpc_vers;
198192067Snwhitehorn	if (nqnfs) {
199192067Snwhitehorn		*tl++ = txdr_unsigned(NQNFS_PROG);
200192067Snwhitehorn		*tl++ = txdr_unsigned(NQNFS_VER1);
201192067Snwhitehorn	} else {
202192067Snwhitehorn		*tl++ = txdr_unsigned(NFS_PROG);
203192067Snwhitehorn		*tl++ = txdr_unsigned(NFS_VER2);
204192067Snwhitehorn	}
205192067Snwhitehorn	*tl++ = txdr_unsigned(procid);
206192067Snwhitehorn
207192067Snwhitehorn	/*
208192067Snwhitehorn	 * And then the authorization cred.
209192067Snwhitehorn	 */
210192067Snwhitehorn	*tl++ = txdr_unsigned(auth_type);
211192067Snwhitehorn	*tl = txdr_unsigned(authsiz);
212192067Snwhitehorn	switch (auth_type) {
213192067Snwhitehorn	case RPCAUTH_UNIX:
214192067Snwhitehorn		nfsm_build(tl, u_long *, auth_len);
215192067Snwhitehorn		*tl++ = 0;		/* stamp ?? */
216192067Snwhitehorn		*tl++ = 0;		/* NULL hostname */
217192067Snwhitehorn		*tl++ = txdr_unsigned(cr->cr_uid);
218192067Snwhitehorn		*tl++ = txdr_unsigned(cr->cr_groups[0]);
219192067Snwhitehorn		grpsiz = (auth_len >> 2) - 5;
220192067Snwhitehorn		*tl++ = txdr_unsigned(grpsiz);
221192067Snwhitehorn		for (i = 1; i <= grpsiz; i++)
222192067Snwhitehorn			*tl++ = txdr_unsigned(cr->cr_groups[i]);
223192067Snwhitehorn		break;
224192067Snwhitehorn	case RPCAUTH_NQNFS:
225192067Snwhitehorn		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
226192067Snwhitehorn		*tl++ = txdr_unsigned(cr->cr_uid);
227192067Snwhitehorn		*tl = txdr_unsigned(auth_len);
228192067Snwhitehorn		siz = auth_len;
229192067Snwhitehorn		while (siz > 0) {
230192067Snwhitehorn			if (M_TRAILINGSPACE(mb) == 0) {
231192067Snwhitehorn				MGET(mb2, M_WAIT, MT_DATA);
232192067Snwhitehorn				if (siz >= MINCLSIZE)
233192067Snwhitehorn					MCLGET(mb2, M_WAIT);
234192067Snwhitehorn				mb->m_next = mb2;
235192067Snwhitehorn				mb = mb2;
236192067Snwhitehorn				mb->m_len = 0;
237				bpos = mtod(mb, caddr_t);
238			}
239			i = min(siz, M_TRAILINGSPACE(mb));
240			bcopy(auth_str, bpos, i);
241			mb->m_len += i;
242			auth_str += i;
243			bpos += i;
244			siz -= i;
245		}
246		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
247			for (i = 0; i < siz; i++)
248				*bpos++ = '\0';
249			mb->m_len += siz;
250		}
251		break;
252	};
253	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
254	*tl++ = txdr_unsigned(RPCAUTH_NULL);
255	*tl = 0;
256	mb->m_next = mrest;
257	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
258	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
259	*mbp = mb;
260	return (mreq);
261}
262
263/*
264 * copies mbuf chain to the uio scatter/gather list
265 */
266int
267nfsm_mbuftouio(mrep, uiop, siz, dpos)
268	struct mbuf **mrep;
269	register struct uio *uiop;
270	int siz;
271	caddr_t *dpos;
272{
273	register char *mbufcp, *uiocp;
274	register int xfer, left, len;
275	register struct mbuf *mp;
276	long uiosiz, rem;
277	int error = 0;
278
279	mp = *mrep;
280	mbufcp = *dpos;
281	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
282	rem = nfsm_rndup(siz)-siz;
283	while (siz > 0) {
284		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
285			return (EFBIG);
286		left = uiop->uio_iov->iov_len;
287		uiocp = uiop->uio_iov->iov_base;
288		if (left > siz)
289			left = siz;
290		uiosiz = left;
291		while (left > 0) {
292			while (len == 0) {
293				mp = mp->m_next;
294				if (mp == NULL)
295					return (EBADRPC);
296				mbufcp = mtod(mp, caddr_t);
297				len = mp->m_len;
298			}
299			xfer = (left > len) ? len : left;
300#ifdef notdef
301			/* Not Yet.. */
302			if (uiop->uio_iov->iov_op != NULL)
303				(*(uiop->uio_iov->iov_op))
304				(mbufcp, uiocp, xfer);
305			else
306#endif
307			if (uiop->uio_segflg == UIO_SYSSPACE)
308				bcopy(mbufcp, uiocp, xfer);
309			else
310				copyout(mbufcp, uiocp, xfer);
311			left -= xfer;
312			len -= xfer;
313			mbufcp += xfer;
314			uiocp += xfer;
315			uiop->uio_offset += xfer;
316			uiop->uio_resid -= xfer;
317		}
318		if (uiop->uio_iov->iov_len <= siz) {
319			uiop->uio_iovcnt--;
320			uiop->uio_iov++;
321		} else {
322			uiop->uio_iov->iov_base += uiosiz;
323			uiop->uio_iov->iov_len -= uiosiz;
324		}
325		siz -= uiosiz;
326	}
327	*dpos = mbufcp;
328	*mrep = mp;
329	if (rem > 0) {
330		if (len < rem)
331			error = nfs_adv(mrep, dpos, rem, len);
332		else
333			*dpos += rem;
334	}
335	return (error);
336}
337
338/*
339 * copies a uio scatter/gather list to an mbuf chain...
340 */
341int
342nfsm_uiotombuf(uiop, mq, siz, bpos)
343	register struct uio *uiop;
344	struct mbuf **mq;
345	int siz;
346	caddr_t *bpos;
347{
348	register char *uiocp;
349	register struct mbuf *mp, *mp2;
350	register int xfer, left, mlen;
351	int uiosiz, clflg, rem;
352	char *cp;
353
354	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
355		clflg = 1;
356	else
357		clflg = 0;
358	rem = nfsm_rndup(siz)-siz;
359	mp = mp2 = *mq;
360	while (siz > 0) {
361		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
362			return (EINVAL);
363		left = uiop->uio_iov->iov_len;
364		uiocp = uiop->uio_iov->iov_base;
365		if (left > siz)
366			left = siz;
367		uiosiz = left;
368		while (left > 0) {
369			mlen = M_TRAILINGSPACE(mp);
370			if (mlen == 0) {
371				MGET(mp, M_WAIT, MT_DATA);
372				if (clflg)
373					MCLGET(mp, M_WAIT);
374				mp->m_len = 0;
375				mp2->m_next = mp;
376				mp2 = mp;
377				mlen = M_TRAILINGSPACE(mp);
378			}
379			xfer = (left > mlen) ? mlen : left;
380#ifdef notdef
381			/* Not Yet.. */
382			if (uiop->uio_iov->iov_op != NULL)
383				(*(uiop->uio_iov->iov_op))
384				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
385			else
386#endif
387			if (uiop->uio_segflg == UIO_SYSSPACE)
388				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
389			else
390				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
391			mp->m_len += xfer;
392			left -= xfer;
393			uiocp += xfer;
394			uiop->uio_offset += xfer;
395			uiop->uio_resid -= xfer;
396		}
397		if (uiop->uio_iov->iov_len <= siz) {
398			uiop->uio_iovcnt--;
399			uiop->uio_iov++;
400		} else {
401			uiop->uio_iov->iov_base += uiosiz;
402			uiop->uio_iov->iov_len -= uiosiz;
403		}
404		siz -= uiosiz;
405	}
406	if (rem > 0) {
407		if (rem > M_TRAILINGSPACE(mp)) {
408			MGET(mp, M_WAIT, MT_DATA);
409			mp->m_len = 0;
410			mp2->m_next = mp;
411		}
412		cp = mtod(mp, caddr_t)+mp->m_len;
413		for (left = 0; left < rem; left++)
414			*cp++ = '\0';
415		mp->m_len += rem;
416		*bpos = cp;
417	} else
418		*bpos = mtod(mp, caddr_t)+mp->m_len;
419	*mq = mp;
420	return (0);
421}
422
423/*
424 * Help break down an mbuf chain by setting the first siz bytes contiguous
425 * pointed to by returned val.
426 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
427 * cases. (The macros use the vars. dpos and dpos2)
428 */
429int
430nfsm_disct(mdp, dposp, siz, left, cp2)
431	struct mbuf **mdp;
432	caddr_t *dposp;
433	int siz;
434	int left;
435	caddr_t *cp2;
436{
437	register struct mbuf *mp, *mp2;
438	register int siz2, xfer;
439	register caddr_t p;
440
441	mp = *mdp;
442	while (left == 0) {
443		*mdp = mp = mp->m_next;
444		if (mp == NULL)
445			return (EBADRPC);
446		left = mp->m_len;
447		*dposp = mtod(mp, caddr_t);
448	}
449	if (left >= siz) {
450		*cp2 = *dposp;
451		*dposp += siz;
452	} else if (mp->m_next == NULL) {
453		return (EBADRPC);
454	} else if (siz > MHLEN) {
455		panic("nfs S too big");
456	} else {
457		MGET(mp2, M_WAIT, MT_DATA);
458		mp2->m_next = mp->m_next;
459		mp->m_next = mp2;
460		mp->m_len -= left;
461		mp = mp2;
462		*cp2 = p = mtod(mp, caddr_t);
463		bcopy(*dposp, p, left);		/* Copy what was left */
464		siz2 = siz-left;
465		p += left;
466		mp2 = mp->m_next;
467		/* Loop around copying up the siz2 bytes */
468		while (siz2 > 0) {
469			if (mp2 == NULL)
470				return (EBADRPC);
471			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
472			if (xfer > 0) {
473				bcopy(mtod(mp2, caddr_t), p, xfer);
474				NFSMADV(mp2, xfer);
475				mp2->m_len -= xfer;
476				p += xfer;
477				siz2 -= xfer;
478			}
479			if (siz2 > 0)
480				mp2 = mp2->m_next;
481		}
482		mp->m_len = siz;
483		*mdp = mp2;
484		*dposp = mtod(mp2, caddr_t);
485	}
486	return (0);
487}
488
489/*
490 * Advance the position in the mbuf chain.
491 */
492int
493nfs_adv(mdp, dposp, offs, left)
494	struct mbuf **mdp;
495	caddr_t *dposp;
496	int offs;
497	int left;
498{
499	register struct mbuf *m;
500	register int s;
501
502	m = *mdp;
503	s = left;
504	while (s < offs) {
505		offs -= s;
506		m = m->m_next;
507		if (m == NULL)
508			return (EBADRPC);
509		s = m->m_len;
510	}
511	*mdp = m;
512	*dposp = mtod(m, caddr_t)+offs;
513	return (0);
514}
515
516/*
517 * Copy a string into mbufs for the hard cases...
518 */
519int
520nfsm_strtmbuf(mb, bpos, cp, siz)
521	struct mbuf **mb;
522	char **bpos;
523	char *cp;
524	long siz;
525{
526	register struct mbuf *m1 = 0, *m2;
527	long left, xfer, len, tlen;
528	u_long *tl;
529	int putsize;
530
531	putsize = 1;
532	m2 = *mb;
533	left = M_TRAILINGSPACE(m2);
534	if (left > 0) {
535		tl = ((u_long *)(*bpos));
536		*tl++ = txdr_unsigned(siz);
537		putsize = 0;
538		left -= NFSX_UNSIGNED;
539		m2->m_len += NFSX_UNSIGNED;
540		if (left > 0) {
541			bcopy(cp, (caddr_t) tl, left);
542			siz -= left;
543			cp += left;
544			m2->m_len += left;
545			left = 0;
546		}
547	}
548	/* Loop around adding mbufs */
549	while (siz > 0) {
550		MGET(m1, M_WAIT, MT_DATA);
551		if (siz > MLEN)
552			MCLGET(m1, M_WAIT);
553		m1->m_len = NFSMSIZ(m1);
554		m2->m_next = m1;
555		m2 = m1;
556		tl = mtod(m1, u_long *);
557		tlen = 0;
558		if (putsize) {
559			*tl++ = txdr_unsigned(siz);
560			m1->m_len -= NFSX_UNSIGNED;
561			tlen = NFSX_UNSIGNED;
562			putsize = 0;
563		}
564		if (siz < m1->m_len) {
565			len = nfsm_rndup(siz);
566			xfer = siz;
567			if (xfer < len)
568				*(tl+(xfer>>2)) = 0;
569		} else {
570			xfer = len = m1->m_len;
571		}
572		bcopy(cp, (caddr_t) tl, xfer);
573		m1->m_len = len+tlen;
574		siz -= xfer;
575		cp += xfer;
576	}
577	*mb = m1;
578	*bpos = mtod(m1, caddr_t)+m1->m_len;
579	return (0);
580}
581
582/*
583 * Called once to initialize data structures...
584 */
585int
586nfs_init()
587{
588	register int i;
589
590	nfsrtt.pos = 0;
591	rpc_vers = txdr_unsigned(RPC_VER2);
592	rpc_call = txdr_unsigned(RPC_CALL);
593	rpc_reply = txdr_unsigned(RPC_REPLY);
594	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
595	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
596	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
597	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
598	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
599	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
600	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
601	nfs_vers = txdr_unsigned(NFS_VER2);
602	nfs_prog = txdr_unsigned(NFS_PROG);
603	nfs_true = txdr_unsigned(TRUE);
604	nfs_false = txdr_unsigned(FALSE);
605	/* Loop thru nfs procids */
606	for (i = 0; i < NFS_NPROCS; i++)
607		nfs_procids[i] = txdr_unsigned(i);
608	/* Ensure async daemons disabled */
609	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
610		nfs_iodwant[i] = (struct proc *)0;
611	TAILQ_INIT(&nfs_bufq);
612	nfs_xdrneg1 = txdr_unsigned(-1);
613	nfs_nhinit();			/* Init the nfsnode table */
614	nfsrv_init(0);			/* Init server data structures */
615	nfsrv_initcache();		/* Init the server request cache */
616
617	/*
618	 * Initialize the nqnfs server stuff.
619	 */
620	if (nqnfsstarttime == 0) {
621		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
622			+ nqsrv_clockskew + nqsrv_writeslack;
623		NQLOADNOVRAM(nqnfsstarttime);
624		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
625		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
626		nqthead.th_head[0] = &nqthead;
627		nqthead.th_head[1] = &nqthead;
628		nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash);
629	}
630
631	/*
632	 * Initialize reply list and start timer
633	 */
634	nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
635	nfs_timer();
636
637	return (0);
638}
639
640/*
641 * Attribute cache routines.
642 * nfs_loadattrcache() - loads or updates the cache contents from attributes
643 *	that are on the mbuf list
644 * nfs_getattrcache() - returns valid attributes if found in cache, returns
645 *	error otherwise
646 */
647
648/*
649 * Load the attribute cache (that lives in the nfsnode entry) with
650 * the values on the mbuf list and
651 * Iff vap not NULL
652 *    copy the attributes to *vaper
653 */
654int
655nfs_loadattrcache(vpp, mdp, dposp, vaper)
656	struct vnode **vpp;
657	struct mbuf **mdp;
658	caddr_t *dposp;
659	struct vattr *vaper;
660{
661	register struct vnode *vp = *vpp;
662	register struct vattr *vap;
663	register struct nfsv2_fattr *fp;
664	extern int (**spec_nfsv2nodeop_p)();
665	register struct nfsnode *np, *nq, **nhpp;
666	register long t1;
667	caddr_t dpos, cp2;
668	int error = 0, isnq;
669	struct mbuf *md;
670	enum vtype vtyp;
671	u_short vmode;
672	long rdev;
673	struct timespec mtime;
674	struct vnode *nvp;
675
676	md = *mdp;
677	dpos = *dposp;
678	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
679	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
680	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2))
681		return (error);
682	fp = (struct nfsv2_fattr *)cp2;
683	vtyp = nfstov_type(fp->fa_type);
684	vmode = fxdr_unsigned(u_short, fp->fa_mode);
685	if (vtyp == VNON || vtyp == VREG)
686		vtyp = IFTOVT(vmode);
687	if (isnq) {
688		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
689		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
690	} else {
691		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
692		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
693	}
694	/*
695	 * If v_type == VNON it is a new node, so fill in the v_type,
696	 * n_mtime fields. Check to see if it represents a special
697	 * device, and if so, check for a possible alias. Once the
698	 * correct vnode has been obtained, fill in the rest of the
699	 * information.
700	 */
701	np = VTONFS(vp);
702	if (vp->v_type == VNON) {
703		if (vtyp == VCHR && rdev == 0xffffffff)
704			vp->v_type = vtyp = VFIFO;
705		else
706			vp->v_type = vtyp;
707		if (vp->v_type == VFIFO) {
708			extern int (**fifo_nfsv2nodeop_p)();
709			vp->v_op = fifo_nfsv2nodeop_p;
710		}
711		if (vp->v_type == VCHR || vp->v_type == VBLK) {
712			vp->v_op = spec_nfsv2nodeop_p;
713			if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
714				/*
715				 * Discard unneeded vnode, but save its nfsnode.
716				 */
717				if (nq = np->n_forw)
718					nq->n_back = np->n_back;
719				*np->n_back = nq;
720				nvp->v_data = vp->v_data;
721				vp->v_data = NULL;
722				vp->v_op = spec_vnodeop_p;
723				vrele(vp);
724				vgone(vp);
725				/*
726				 * Reinitialize aliased node.
727				 */
728				np->n_vnode = nvp;
729				nhpp = (struct nfsnode **)nfs_hash(&np->n_fh);
730				if (nq = *nhpp)
731					nq->n_back = &np->n_forw;
732				np->n_forw = nq;
733				np->n_back = nhpp;
734				*nhpp = np;
735				*vpp = vp = nvp;
736			}
737		}
738		np->n_mtime = mtime.ts_sec;
739	}
740	vap = &np->n_vattr;
741	vap->va_type = vtyp;
742	vap->va_mode = (vmode & 07777);
743	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
744	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
745	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
746	vap->va_rdev = (dev_t)rdev;
747	vap->va_mtime = mtime;
748	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
749	if (isnq) {
750		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
751		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
752		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
753		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
754		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
755		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
756		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
757		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
758		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
759	} else {
760		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
761		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
762		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
763		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
764		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
765		vap->va_flags = 0;
766		vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec);
767		vap->va_ctime.ts_nsec = 0;
768		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec);
769		vap->va_filerev = 0;
770	}
771	if (vap->va_size != np->n_size) {
772		if (vap->va_type == VREG) {
773			if (np->n_flag & NMODIFIED) {
774				if (vap->va_size < np->n_size)
775					vap->va_size = np->n_size;
776				else
777					np->n_size = vap->va_size;
778			} else
779				np->n_size = vap->va_size;
780			vnode_pager_setsize(vp, (u_long)np->n_size);
781		} else
782			np->n_size = vap->va_size;
783	}
784	np->n_attrstamp = time.tv_sec;
785	*dposp = dpos;
786	*mdp = md;
787	if (vaper != NULL) {
788		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
789#ifdef notdef
790		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
791		if (np->n_size > vap->va_size)
792			vaper->va_size = np->n_size;
793#endif
794		if (np->n_flag & NCHG) {
795			if (np->n_flag & NACC) {
796				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
797				vaper->va_atime.ts_nsec =
798				    np->n_atim.tv_usec * 1000;
799			}
800			if (np->n_flag & NUPD) {
801				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
802				vaper->va_mtime.ts_nsec =
803				    np->n_mtim.tv_usec * 1000;
804			}
805		}
806	}
807	return (0);
808}
809
810/*
811 * Check the time stamp
812 * If the cache is valid, copy contents to *vap and return 0
813 * otherwise return an error
814 */
815int
816nfs_getattrcache(vp, vaper)
817	register struct vnode *vp;
818	struct vattr *vaper;
819{
820	register struct nfsnode *np = VTONFS(vp);
821	register struct vattr *vap;
822
823	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
824		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
825			nfsstats.attrcache_misses++;
826			return (ENOENT);
827		}
828	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
829		nfsstats.attrcache_misses++;
830		return (ENOENT);
831	}
832	nfsstats.attrcache_hits++;
833	vap = &np->n_vattr;
834	if (vap->va_size != np->n_size) {
835		if (vap->va_type == VREG) {
836			if (np->n_flag & NMODIFIED) {
837				if (vap->va_size < np->n_size)
838					vap->va_size = np->n_size;
839				else
840					np->n_size = vap->va_size;
841			} else
842				np->n_size = vap->va_size;
843			vnode_pager_setsize(vp, (u_long)np->n_size);
844		} else
845			np->n_size = vap->va_size;
846	}
847	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
848#ifdef notdef
849	if ((np->n_flag & NMODIFIED) == 0) {
850		np->n_size = vaper->va_size;
851		vnode_pager_setsize(vp, (u_long)np->n_size);
852	} else if (np->n_size > vaper->va_size)
853	if (np->n_size > vaper->va_size)
854		vaper->va_size = np->n_size;
855#endif
856	if (np->n_flag & NCHG) {
857		if (np->n_flag & NACC) {
858			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
859			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
860		}
861		if (np->n_flag & NUPD) {
862			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
863			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
864		}
865	}
866	return (0);
867}
868
869/*
870 * Set up nameidata for a lookup() call and do it
871 */
872int
873nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
874	register struct nameidata *ndp;
875	fhandle_t *fhp;
876	int len;
877	struct nfssvc_sock *slp;
878	struct mbuf *nam;
879	struct mbuf **mdp;
880	caddr_t *dposp;
881	struct proc *p;
882{
883	register int i, rem;
884	register struct mbuf *md;
885	register char *fromcp, *tocp;
886	struct vnode *dp;
887	int error, rdonly;
888	struct componentname *cnp = &ndp->ni_cnd;
889
890	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
891	/*
892	 * Copy the name from the mbuf list to ndp->ni_pnbuf
893	 * and set the various ndp fields appropriately.
894	 */
895	fromcp = *dposp;
896	tocp = cnp->cn_pnbuf;
897	md = *mdp;
898	rem = mtod(md, caddr_t) + md->m_len - fromcp;
899	cnp->cn_hash = 0;
900	for (i = 0; i < len; i++) {
901		while (rem == 0) {
902			md = md->m_next;
903			if (md == NULL) {
904				error = EBADRPC;
905				goto out;
906			}
907			fromcp = mtod(md, caddr_t);
908			rem = md->m_len;
909		}
910		if (*fromcp == '\0' || *fromcp == '/') {
911			error = EINVAL;
912			goto out;
913		}
914		cnp->cn_hash += (unsigned char)*fromcp;
915		*tocp++ = *fromcp++;
916		rem--;
917	}
918	*tocp = '\0';
919	*mdp = md;
920	*dposp = fromcp;
921	len = nfsm_rndup(len)-len;
922	if (len > 0) {
923		if (rem >= len)
924			*dposp += len;
925		else if (error = nfs_adv(mdp, dposp, len, rem))
926			goto out;
927	}
928	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
929	cnp->cn_nameptr = cnp->cn_pnbuf;
930	/*
931	 * Extract and set starting directory.
932	 */
933	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
934	    nam, &rdonly))
935		goto out;
936	if (dp->v_type != VDIR) {
937		vrele(dp);
938		error = ENOTDIR;
939		goto out;
940	}
941	ndp->ni_startdir = dp;
942	if (rdonly)
943		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
944	else
945		cnp->cn_flags |= NOCROSSMOUNT;
946	/*
947	 * And call lookup() to do the real work
948	 */
949	cnp->cn_proc = p;
950	if (error = lookup(ndp))
951		goto out;
952	/*
953	 * Check for encountering a symbolic link
954	 */
955	if (cnp->cn_flags & ISSYMLINK) {
956		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
957			vput(ndp->ni_dvp);
958		else
959			vrele(ndp->ni_dvp);
960		vput(ndp->ni_vp);
961		ndp->ni_vp = NULL;
962		error = EINVAL;
963		goto out;
964	}
965	/*
966	 * Check for saved name request
967	 */
968	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
969		cnp->cn_flags |= HASBUF;
970		return (0);
971	}
972out:
973	FREE(cnp->cn_pnbuf, M_NAMEI);
974	return (error);
975}
976
977/*
978 * A fiddled version of m_adj() that ensures null fill to a long
979 * boundary and only trims off the back end
980 */
981void
982nfsm_adj(mp, len, nul)
983	struct mbuf *mp;
984	register int len;
985	int nul;
986{
987	register struct mbuf *m;
988	register int count, i;
989	register char *cp;
990
991	/*
992	 * Trim from tail.  Scan the mbuf chain,
993	 * calculating its length and finding the last mbuf.
994	 * If the adjustment only affects this mbuf, then just
995	 * adjust and return.  Otherwise, rescan and truncate
996	 * after the remaining size.
997	 */
998	count = 0;
999	m = mp;
1000	for (;;) {
1001		count += m->m_len;
1002		if (m->m_next == (struct mbuf *)0)
1003			break;
1004		m = m->m_next;
1005	}
1006	if (m->m_len > len) {
1007		m->m_len -= len;
1008		if (nul > 0) {
1009			cp = mtod(m, caddr_t)+m->m_len-nul;
1010			for (i = 0; i < nul; i++)
1011				*cp++ = '\0';
1012		}
1013		return;
1014	}
1015	count -= len;
1016	if (count < 0)
1017		count = 0;
1018	/*
1019	 * Correct length for chain is "count".
1020	 * Find the mbuf with last data, adjust its length,
1021	 * and toss data from remaining mbufs on chain.
1022	 */
1023	for (m = mp; m; m = m->m_next) {
1024		if (m->m_len >= count) {
1025			m->m_len = count;
1026			if (nul > 0) {
1027				cp = mtod(m, caddr_t)+m->m_len-nul;
1028				for (i = 0; i < nul; i++)
1029					*cp++ = '\0';
1030			}
1031			break;
1032		}
1033		count -= m->m_len;
1034	}
1035	while (m = m->m_next)
1036		m->m_len = 0;
1037}
1038
1039/*
1040 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1041 * 	- look up fsid in mount list (if not found ret error)
1042 *	- get vp and export rights by calling VFS_FHTOVP()
1043 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1044 *	- if not lockflag unlock it with VOP_UNLOCK()
1045 */
1046int
1047nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
1048	fhandle_t *fhp;
1049	int lockflag;
1050	struct vnode **vpp;
1051	struct ucred *cred;
1052	struct nfssvc_sock *slp;
1053	struct mbuf *nam;
1054	int *rdonlyp;
1055{
1056	register struct mount *mp;
1057	register struct nfsuid *uidp;
1058	register int i;
1059	struct ucred *credanon;
1060	int error, exflags;
1061
1062	*vpp = (struct vnode *)0;
1063	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
1064		return (ESTALE);
1065	if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon))
1066		return (error);
1067	/*
1068	 * Check/setup credentials.
1069	 */
1070	if (exflags & MNT_EXKERB) {
1071		uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
1072		while (uidp) {
1073			if (uidp->nu_uid == cred->cr_uid)
1074				break;
1075			uidp = uidp->nu_hnext;
1076		}
1077		if (uidp) {
1078			cred->cr_uid = uidp->nu_cr.cr_uid;
1079			for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
1080				cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
1081		} else {
1082			vput(*vpp);
1083			return (NQNFS_AUTHERR);
1084		}
1085	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1086		cred->cr_uid = credanon->cr_uid;
1087		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1088			cred->cr_groups[i] = credanon->cr_groups[i];
1089	}
1090	if (exflags & MNT_EXRDONLY)
1091		*rdonlyp = 1;
1092	else
1093		*rdonlyp = 0;
1094	if (!lockflag)
1095		VOP_UNLOCK(*vpp);
1096	return (0);
1097}
1098
1099/*
1100 * This function compares two net addresses by family and returns TRUE
1101 * if they are the same host.
1102 * If there is any doubt, return FALSE.
1103 * The AF_INET family is handled as a special case so that address mbufs
1104 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1105 */
1106int
1107netaddr_match(family, haddr, nam)
1108	int family;
1109	union nethostaddr *haddr;
1110	struct mbuf *nam;
1111{
1112	register struct sockaddr_in *inetaddr;
1113
1114	switch (family) {
1115	case AF_INET:
1116		inetaddr = mtod(nam, struct sockaddr_in *);
1117		if (inetaddr->sin_family == AF_INET &&
1118		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1119			return (1);
1120		break;
1121#ifdef ISO
1122	case AF_ISO:
1123	    {
1124		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1125
1126		isoaddr1 = mtod(nam, struct sockaddr_iso *);
1127		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1128		if (isoaddr1->siso_family == AF_ISO &&
1129		    isoaddr1->siso_nlen > 0 &&
1130		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1131		    SAME_ISOADDR(isoaddr1, isoaddr2))
1132			return (1);
1133		break;
1134	    }
1135#endif	/* ISO */
1136	default:
1137		break;
1138	};
1139	return (0);
1140}
1141