nfs_nfsiod.c revision 19449
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_syscalls.c	8.3 (Berkeley) 1/4/94
3719449Sdfr * $Id: nfs_syscalls.c,v 1.14 1996/04/30 23:26:52 bde Exp $
381541Srgrimes */
391541Srgrimes
401541Srgrimes#include <sys/param.h>
411541Srgrimes#include <sys/systm.h>
4212274Sbde#include <sys/sysproto.h>
431541Srgrimes#include <sys/kernel.h>
4419449Sdfr#include <sys/sysctl.h>
451541Srgrimes#include <sys/file.h>
4615480Sbde#include <sys/filedesc.h>
471541Srgrimes#include <sys/stat.h>
481541Srgrimes#include <sys/vnode.h>
491541Srgrimes#include <sys/mount.h>
501541Srgrimes#include <sys/proc.h>
511541Srgrimes#include <sys/uio.h>
521541Srgrimes#include <sys/malloc.h>
531541Srgrimes#include <sys/buf.h>
541541Srgrimes#include <sys/mbuf.h>
551541Srgrimes#include <sys/socket.h>
561541Srgrimes#include <sys/socketvar.h>
571541Srgrimes#include <sys/domain.h>
581541Srgrimes#include <sys/protosw.h>
591541Srgrimes#include <sys/namei.h>
601541Srgrimes#include <sys/syslog.h>
611541Srgrimes
621541Srgrimes#include <netinet/in.h>
631541Srgrimes#include <netinet/tcp.h>
641541Srgrimes#ifdef ISO
651541Srgrimes#include <netiso/iso.h>
661541Srgrimes#endif
679336Sdfr#include <nfs/xdr_subs.h>
681541Srgrimes#include <nfs/rpcv2.h>
699336Sdfr#include <nfs/nfsproto.h>
701541Srgrimes#include <nfs/nfs.h>
719336Sdfr#include <nfs/nfsm_subs.h>
721541Srgrimes#include <nfs/nfsrvcache.h>
731541Srgrimes#include <nfs/nfsmount.h>
741541Srgrimes#include <nfs/nfsnode.h>
751541Srgrimes#include <nfs/nqnfs.h>
761541Srgrimes#include <nfs/nfsrtt.h>
771541Srgrimes
781541Srgrimes/* Global defs. */
7912457Sbdeextern int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd,
8012457Sbde					    struct nfssvc_sock *slp,
8112457Sbde					    struct proc *procp,
8212457Sbde					    struct mbuf **mreqp));
831541Srgrimesextern int nfs_numasync;
841541Srgrimesextern time_t nqnfsstarttime;
851541Srgrimesextern int nqsrv_writeslack;
861541Srgrimesextern int nfsrtton;
879336Sdfrextern struct nfsstats nfsstats;
889336Sdfrextern int nfsrvw_procrastinate;
891541Srgrimesstruct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
9012911Sphkstatic int nuidhash_max = NFS_MAXUIDHASH;
911541Srgrimes
9212911Sphkstatic void	nfsrv_zapsock __P((struct nfssvc_sock *slp));
9313416Sphkstatic int	nfssvc_iod __P((struct proc *));
9412457Sbde
951541Srgrimes#define	TRUE	1
961541Srgrimes#define	FALSE	0
971541Srgrimes
981541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
9912457Sbde
10013416Sphk
10113416Sphk#ifndef NFS_NOSERVER
10213416Sphkint nfsd_waiting = 0;
10313416Sphkstatic struct nfsdrt nfsdrt;
10413416Sphkstatic int nfs_numnfsd = 0;
10513416Sphkstatic int notstarted = 1;
10613416Sphkstatic int modify_flag = 0;
10712457Sbdestatic void	nfsd_rt __P((int sotype, struct nfsrv_descript *nd,
10812457Sbde			     int cacherep));
10912911Sphkstatic int	nfssvc_addsock __P((struct file *,struct mbuf *));
11012911Sphkstatic int	nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *));
1111541Srgrimes/*
1121541Srgrimes * NFS server system calls
1131541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
1141541Srgrimes */
1151541Srgrimes
1161541Srgrimes/*
1171541Srgrimes * Get file handle system call
1181541Srgrimes */
11912274Sbde#ifndef _SYS_SYSPROTO_H_
1201541Srgrimesstruct getfh_args {
1211541Srgrimes	char	*fname;
1221541Srgrimes	fhandle_t *fhp;
1231541Srgrimes};
12412274Sbde#endif
1251549Srgrimesint
1261541Srgrimesgetfh(p, uap, retval)
1271541Srgrimes	struct proc *p;
1281541Srgrimes	register struct getfh_args *uap;
1291541Srgrimes	int *retval;
1301541Srgrimes{
1311541Srgrimes	register struct vnode *vp;
1321541Srgrimes	fhandle_t fh;
1331541Srgrimes	int error;
1341541Srgrimes	struct nameidata nd;
1351541Srgrimes
1361541Srgrimes	/*
1371541Srgrimes	 * Must be super user
1381541Srgrimes	 */
1393305Sphk	error = suser(p->p_ucred, &p->p_acflag);
1403305Sphk	if(error)
1411541Srgrimes		return (error);
1421541Srgrimes	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1433305Sphk	error = namei(&nd);
1443305Sphk	if (error)
1451541Srgrimes		return (error);
1461541Srgrimes	vp = nd.ni_vp;
1471541Srgrimes	bzero((caddr_t)&fh, sizeof(fh));
1481541Srgrimes	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1491541Srgrimes	error = VFS_VPTOFH(vp, &fh.fh_fid);
1501541Srgrimes	vput(vp);
1511541Srgrimes	if (error)
1521541Srgrimes		return (error);
1531541Srgrimes	error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
1541541Srgrimes	return (error);
1551541Srgrimes}
1561541Srgrimes
15713416Sphk#endif /* NFS_NOSERVER */
1581541Srgrimes/*
1591541Srgrimes * Nfs server psuedo system call for the nfsd's
1601541Srgrimes * Based on the flag value it either:
1611541Srgrimes * - adds a socket to the selection list
1621541Srgrimes * - remains in the kernel as an nfsd
1631541Srgrimes * - remains in the kernel as an nfsiod
1641541Srgrimes */
16512274Sbde#ifndef _SYS_SYSPROTO_H_
1661541Srgrimesstruct nfssvc_args {
1671541Srgrimes	int flag;
1681541Srgrimes	caddr_t argp;
1691541Srgrimes};
17012274Sbde#endif
1711549Srgrimesint
1721541Srgrimesnfssvc(p, uap, retval)
1731541Srgrimes	struct proc *p;
1741541Srgrimes	register struct nfssvc_args *uap;
1751541Srgrimes	int *retval;
1761541Srgrimes{
17713416Sphk#ifndef NFS_NOSERVER
1781541Srgrimes	struct nameidata nd;
1791541Srgrimes	struct file *fp;
1801541Srgrimes	struct mbuf *nam;
1811541Srgrimes	struct nfsd_args nfsdarg;
1821541Srgrimes	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
1831541Srgrimes	struct nfsd_cargs ncd;
1841541Srgrimes	struct nfsd *nfsd;
1851541Srgrimes	struct nfssvc_sock *slp;
1863664Sphk	struct nfsuid *nuidp;
1871541Srgrimes	struct nfsmount *nmp;
18813416Sphk#endif /* NFS_NOSERVER */
1891541Srgrimes	int error;
1901541Srgrimes
1911541Srgrimes	/*
1921541Srgrimes	 * Must be super user
1931541Srgrimes	 */
1943305Sphk	error = suser(p->p_ucred, &p->p_acflag);
1953305Sphk	if(error)
1961541Srgrimes		return (error);
1973664Sphk	while (nfssvc_sockhead_flag & SLP_INIT) {
1983664Sphk		 nfssvc_sockhead_flag |= SLP_WANTINIT;
1991541Srgrimes		(void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
2001541Srgrimes	}
2011541Srgrimes	if (uap->flag & NFSSVC_BIOD)
2021541Srgrimes		error = nfssvc_iod(p);
20313416Sphk#ifdef NFS_NOSERVER
20413416Sphk	else
20513416Sphk		error = ENXIO;
20613416Sphk#else /* !NFS_NOSERVER */
2071541Srgrimes	else if (uap->flag & NFSSVC_MNTD) {
2083305Sphk		error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd));
2093305Sphk		if (error)
2101541Srgrimes			return (error);
2111541Srgrimes		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2121541Srgrimes			ncd.ncd_dirp, p);
2133305Sphk		error = namei(&nd);
2143305Sphk		if (error)
2151541Srgrimes			return (error);
2161541Srgrimes		if ((nd.ni_vp->v_flag & VROOT) == 0)
2171541Srgrimes			error = EINVAL;
2181541Srgrimes		nmp = VFSTONFS(nd.ni_vp->v_mount);
2191541Srgrimes		vput(nd.ni_vp);
2201541Srgrimes		if (error)
2211541Srgrimes			return (error);
2221541Srgrimes		if ((nmp->nm_flag & NFSMNT_MNTD) &&
2231541Srgrimes			(uap->flag & NFSSVC_GOTAUTH) == 0)
2241541Srgrimes			return (0);
2251541Srgrimes		nmp->nm_flag |= NFSMNT_MNTD;
2261541Srgrimes		error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
2271541Srgrimes			uap->argp, p);
2281541Srgrimes	} else if (uap->flag & NFSSVC_ADDSOCK) {
2293305Sphk		error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
2303305Sphk		if (error)
2311541Srgrimes			return (error);
2323305Sphk		error = getsock(p->p_fd, nfsdarg.sock, &fp);
2333305Sphk		if (error)
2341541Srgrimes			return (error);
2351541Srgrimes		/*
2361541Srgrimes		 * Get the client address for connected sockets.
2371541Srgrimes		 */
2381541Srgrimes		if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
2391541Srgrimes			nam = (struct mbuf *)0;
2403305Sphk		else {
2413305Sphk			error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
2423305Sphk				MT_SONAME);
2433305Sphk			if (error)
2443305Sphk				return (error);
2453305Sphk		}
2461541Srgrimes		error = nfssvc_addsock(fp, nam);
2471541Srgrimes	} else {
2483305Sphk		error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd));
2493305Sphk		if (error)
2501541Srgrimes			return (error);
2513305Sphk		if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) &&
2529336Sdfr			(nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
2539336Sdfr			slp = nfsd->nfsd_slp;
2541541Srgrimes
2551541Srgrimes			/*
2561541Srgrimes			 * First check to see if another nfsd has already
2571541Srgrimes			 * added this credential.
2581541Srgrimes			 */
2599336Sdfr			for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
2603664Sphk			    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
2619336Sdfr				if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
2629336Sdfr				    (!nfsd->nfsd_nd->nd_nam2 ||
2639336Sdfr				     netaddr_match(NU_NETFAM(nuidp),
2649336Sdfr				     &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
2651541Srgrimes					break;
2661541Srgrimes			}
2679336Sdfr			if (nuidp) {
2689336Sdfr			    nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
2699336Sdfr			    nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
2709336Sdfr			} else {
2711541Srgrimes			    /*
2721541Srgrimes			     * Nope, so we will.
2731541Srgrimes			     */
2741541Srgrimes			    if (slp->ns_numuids < nuidhash_max) {
2751541Srgrimes				slp->ns_numuids++;
2761541Srgrimes				nuidp = (struct nfsuid *)
2771541Srgrimes				   malloc(sizeof (struct nfsuid), M_NFSUID,
2781541Srgrimes					M_WAITOK);
2791541Srgrimes			    } else
2801541Srgrimes				nuidp = (struct nfsuid *)0;
2811541Srgrimes			    if ((slp->ns_flag & SLP_VALID) == 0) {
2821541Srgrimes				if (nuidp)
2831541Srgrimes				    free((caddr_t)nuidp, M_NFSUID);
2841541Srgrimes			    } else {
2851541Srgrimes				if (nuidp == (struct nfsuid *)0) {
2863664Sphk				    nuidp = slp->ns_uidlruhead.tqh_first;
2873664Sphk				    LIST_REMOVE(nuidp, nu_hash);
2883664Sphk				    TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
2893664Sphk					nu_lru);
2909336Sdfr				    if (nuidp->nu_flag & NU_NAM)
2919336Sdfr					m_freem(nuidp->nu_nam);
2921541Srgrimes			        }
2939336Sdfr				nuidp->nu_flag = 0;
2941541Srgrimes				nuidp->nu_cr = nsd->nsd_cr;
2951541Srgrimes				if (nuidp->nu_cr.cr_ngroups > NGROUPS)
2969336Sdfr				    nuidp->nu_cr.cr_ngroups = NGROUPS;
2971541Srgrimes				nuidp->nu_cr.cr_ref = 1;
2989336Sdfr				nuidp->nu_timestamp = nsd->nsd_timestamp;
2999336Sdfr				nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl;
3009336Sdfr				/*
3019336Sdfr				 * and save the session key in nu_key.
3029336Sdfr				 */
3039336Sdfr				bcopy(nsd->nsd_key, nuidp->nu_key,
3049336Sdfr				    sizeof (nsd->nsd_key));
3059336Sdfr				if (nfsd->nfsd_nd->nd_nam2) {
3069336Sdfr				    struct sockaddr_in *saddr;
3079336Sdfr
3089336Sdfr				    saddr = mtod(nfsd->nfsd_nd->nd_nam2,
3099336Sdfr					 struct sockaddr_in *);
3109336Sdfr				    switch (saddr->sin_family) {
3119336Sdfr				    case AF_INET:
3129336Sdfr					nuidp->nu_flag |= NU_INETADDR;
3139336Sdfr					nuidp->nu_inetaddr =
3149336Sdfr					     saddr->sin_addr.s_addr;
3159336Sdfr					break;
3169336Sdfr				    case AF_ISO:
3179336Sdfr				    default:
3189336Sdfr					nuidp->nu_flag |= NU_NAM;
3199336Sdfr					nuidp->nu_nam = m_copym(
3209336Sdfr					    nfsd->nfsd_nd->nd_nam2, 0,
3219336Sdfr					     M_COPYALL, M_WAIT);
3229336Sdfr					break;
3239336Sdfr				    };
3249336Sdfr				}
3253664Sphk				TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
3263664Sphk					nu_lru);
3273664Sphk				LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
3283664Sphk					nuidp, nu_hash);
3299336Sdfr				nfsrv_setcred(&nuidp->nu_cr,
3309336Sdfr				    &nfsd->nfsd_nd->nd_cr);
3319336Sdfr				nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
3321541Srgrimes			    }
3331541Srgrimes			}
3341541Srgrimes		}
3351541Srgrimes		if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
3369336Sdfr			nfsd->nfsd_flag |= NFSD_AUTHFAIL;
3371541Srgrimes		error = nfssvc_nfsd(nsd, uap->argp, p);
3381541Srgrimes	}
33913416Sphk#endif /* NFS_NOSERVER */
3401541Srgrimes	if (error == EINTR || error == ERESTART)
3411541Srgrimes		error = 0;
3421541Srgrimes	return (error);
3431541Srgrimes}
3441541Srgrimes
34513416Sphk#ifndef NFS_NOSERVER
3461541Srgrimes/*
3471541Srgrimes * Adds a socket to the list for servicing by nfsds.
3481541Srgrimes */
34912911Sphkstatic int
3501541Srgrimesnfssvc_addsock(fp, mynam)
3511541Srgrimes	struct file *fp;
3521541Srgrimes	struct mbuf *mynam;
3531541Srgrimes{
3541541Srgrimes	register struct mbuf *m;
3551541Srgrimes	register int siz;
3561541Srgrimes	register struct nfssvc_sock *slp;
3571541Srgrimes	register struct socket *so;
3581541Srgrimes	struct nfssvc_sock *tslp;
3591541Srgrimes	int error, s;
3601541Srgrimes
3611541Srgrimes	so = (struct socket *)fp->f_data;
3621541Srgrimes	tslp = (struct nfssvc_sock *)0;
3631541Srgrimes	/*
3641541Srgrimes	 * Add it to the list, as required.
3651541Srgrimes	 */
3661541Srgrimes	if (so->so_proto->pr_protocol == IPPROTO_UDP) {
3671541Srgrimes		tslp = nfs_udpsock;
3681541Srgrimes		if (tslp->ns_flag & SLP_VALID) {
3691541Srgrimes			m_freem(mynam);
3701541Srgrimes			return (EPERM);
3711541Srgrimes		}
3721541Srgrimes#ifdef ISO
3731541Srgrimes	} else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
3741541Srgrimes		tslp = nfs_cltpsock;
3751541Srgrimes		if (tslp->ns_flag & SLP_VALID) {
3761541Srgrimes			m_freem(mynam);
3771541Srgrimes			return (EPERM);
3781541Srgrimes		}
3791541Srgrimes#endif /* ISO */
3801541Srgrimes	}
3811541Srgrimes	if (so->so_type == SOCK_STREAM)
3821541Srgrimes		siz = NFS_MAXPACKET + sizeof (u_long);
3831541Srgrimes	else
3841541Srgrimes		siz = NFS_MAXPACKET;
3858876Srgrimes	error = soreserve(so, siz, siz);
3863305Sphk	if (error) {
3871541Srgrimes		m_freem(mynam);
3881541Srgrimes		return (error);
3891541Srgrimes	}
3901541Srgrimes
3911541Srgrimes	/*
3921541Srgrimes	 * Set protocol specific options { for now TCP only } and
3931541Srgrimes	 * reserve some space. For datagram sockets, this can get called
3941541Srgrimes	 * repeatedly for the same socket, but that isn't harmful.
3951541Srgrimes	 */
3961541Srgrimes	if (so->so_type == SOCK_STREAM) {
3971541Srgrimes		MGET(m, M_WAIT, MT_SOOPTS);
3981541Srgrimes		*mtod(m, int *) = 1;
3991541Srgrimes		m->m_len = sizeof(int);
4001541Srgrimes		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
4011541Srgrimes	}
4021541Srgrimes	if (so->so_proto->pr_domain->dom_family == AF_INET &&
4031541Srgrimes	    so->so_proto->pr_protocol == IPPROTO_TCP) {
4041541Srgrimes		MGET(m, M_WAIT, MT_SOOPTS);
4051541Srgrimes		*mtod(m, int *) = 1;
4061541Srgrimes		m->m_len = sizeof(int);
4071541Srgrimes		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
4081541Srgrimes	}
4091541Srgrimes	so->so_rcv.sb_flags &= ~SB_NOINTR;
4101541Srgrimes	so->so_rcv.sb_timeo = 0;
4111541Srgrimes	so->so_snd.sb_flags &= ~SB_NOINTR;
4121541Srgrimes	so->so_snd.sb_timeo = 0;
4131541Srgrimes	if (tslp)
4141541Srgrimes		slp = tslp;
4151541Srgrimes	else {
4161541Srgrimes		slp = (struct nfssvc_sock *)
4171541Srgrimes			malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
4181541Srgrimes		bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
4193664Sphk		TAILQ_INIT(&slp->ns_uidlruhead);
4203664Sphk		TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
4211541Srgrimes	}
4221541Srgrimes	slp->ns_so = so;
4231541Srgrimes	slp->ns_nam = mynam;
4241541Srgrimes	fp->f_count++;
4251541Srgrimes	slp->ns_fp = fp;
4261541Srgrimes	s = splnet();
4271541Srgrimes	so->so_upcallarg = (caddr_t)slp;
4281541Srgrimes	so->so_upcall = nfsrv_rcv;
4291541Srgrimes	slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
4301541Srgrimes	nfsrv_wakenfsd(slp);
4311541Srgrimes	splx(s);
4321541Srgrimes	return (0);
4331541Srgrimes}
4341541Srgrimes
4351541Srgrimes/*
4361541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
4371541Srgrimes * until it is killed by a signal.
4381541Srgrimes */
43912911Sphkstatic int
4401541Srgrimesnfssvc_nfsd(nsd, argp, p)
4411541Srgrimes	struct nfsd_srvargs *nsd;
4421541Srgrimes	caddr_t argp;
4431541Srgrimes	struct proc *p;
4441541Srgrimes{
4459336Sdfr	register struct mbuf *m;
4461541Srgrimes	register int siz;
4471541Srgrimes	register struct nfssvc_sock *slp;
4481541Srgrimes	register struct socket *so;
4491541Srgrimes	register int *solockp;
4509336Sdfr	struct nfsd *nfsd = nsd->nsd_nfsd;
4519336Sdfr	struct nfsrv_descript *nd = NULL;
4529336Sdfr	struct mbuf *mreq;
4539336Sdfr	int error = 0, cacherep, s, sotype, writes_todo;
4549336Sdfr	u_quad_t cur_usec;
4551541Srgrimes
4569336Sdfr#ifndef nolint
4579336Sdfr	cacherep = RC_DOIT;
4589336Sdfr	writes_todo = 0;
4599336Sdfr#endif
4601541Srgrimes	s = splnet();
4619336Sdfr	if (nfsd == (struct nfsd *)0) {
4629336Sdfr		nsd->nsd_nfsd = nfsd = (struct nfsd *)
4631541Srgrimes			malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
4649336Sdfr		bzero((caddr_t)nfsd, sizeof (struct nfsd));
4659336Sdfr		nfsd->nfsd_procp = p;
4669336Sdfr		TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
4671541Srgrimes		nfs_numnfsd++;
4681541Srgrimes	}
4691541Srgrimes	/*
4701541Srgrimes	 * Loop getting rpc requests until SIGKILL.
4711541Srgrimes	 */
4721541Srgrimes	for (;;) {
4739336Sdfr		if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
4749336Sdfr			while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
4753664Sphk			    (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
4769336Sdfr				nfsd->nfsd_flag |= NFSD_WAITING;
4771541Srgrimes				nfsd_waiting++;
4789336Sdfr				error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
4799336Sdfr				    "nfsd", 0);
4801541Srgrimes				nfsd_waiting--;
4811541Srgrimes				if (error)
4821541Srgrimes					goto done;
4831541Srgrimes			}
4849336Sdfr			if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
4853664Sphk			    (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
4863664Sphk				for (slp = nfssvc_sockhead.tqh_first; slp != 0;
4873664Sphk				    slp = slp->ns_chain.tqe_next) {
4881541Srgrimes				    if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
4891541Srgrimes					== (SLP_VALID | SLP_DOREC)) {
4901541Srgrimes					    slp->ns_flag &= ~SLP_DOREC;
4911541Srgrimes					    slp->ns_sref++;
4929336Sdfr					    nfsd->nfsd_slp = slp;
4931541Srgrimes					    break;
4941541Srgrimes				    }
4951541Srgrimes				}
4963664Sphk				if (slp == 0)
4973664Sphk					nfsd_head_flag &= ~NFSD_CHECKSLP;
4981541Srgrimes			}
4999336Sdfr			if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
5001541Srgrimes				continue;
5011541Srgrimes			if (slp->ns_flag & SLP_VALID) {
5021541Srgrimes				if (slp->ns_flag & SLP_DISCONN)
5031541Srgrimes					nfsrv_zapsock(slp);
5041541Srgrimes				else if (slp->ns_flag & SLP_NEEDQ) {
5051541Srgrimes					slp->ns_flag &= ~SLP_NEEDQ;
5061541Srgrimes					(void) nfs_sndlock(&slp->ns_solock,
5071541Srgrimes						(struct nfsreq *)0);
5081541Srgrimes					nfsrv_rcv(slp->ns_so, (caddr_t)slp,
5091541Srgrimes						M_WAIT);
5101541Srgrimes					nfs_sndunlock(&slp->ns_solock);
5111541Srgrimes				}
5129336Sdfr				error = nfsrv_dorec(slp, nfsd, &nd);
5139336Sdfr				cur_usec = (u_quad_t)time.tv_sec * 1000000 +
5149336Sdfr					(u_quad_t)time.tv_usec;
5159336Sdfr				if (error && slp->ns_tq.lh_first &&
5169336Sdfr				    slp->ns_tq.lh_first->nd_time <= cur_usec) {
5179336Sdfr					error = 0;
5189336Sdfr					cacherep = RC_DOIT;
5199336Sdfr					writes_todo = 1;
5209336Sdfr				} else
5219336Sdfr					writes_todo = 0;
5229336Sdfr				nfsd->nfsd_flag |= NFSD_REQINPROG;
5231541Srgrimes			}
5241541Srgrimes		} else {
5251541Srgrimes			error = 0;
5269336Sdfr			slp = nfsd->nfsd_slp;
5271541Srgrimes		}
5281541Srgrimes		if (error || (slp->ns_flag & SLP_VALID) == 0) {
5299336Sdfr			if (nd) {
5309336Sdfr				free((caddr_t)nd, M_NFSRVDESC);
5319336Sdfr				nd = NULL;
5329336Sdfr			}
5339336Sdfr			nfsd->nfsd_slp = (struct nfssvc_sock *)0;
5349336Sdfr			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
5351541Srgrimes			nfsrv_slpderef(slp);
5361541Srgrimes			continue;
5371541Srgrimes		}
5381541Srgrimes		splx(s);
5391541Srgrimes		so = slp->ns_so;
5401541Srgrimes		sotype = so->so_type;
5411541Srgrimes		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
5421541Srgrimes			solockp = &slp->ns_solock;
5431541Srgrimes		else
5441541Srgrimes			solockp = (int *)0;
5459336Sdfr		if (nd) {
5469336Sdfr		    nd->nd_starttime = time;
5479336Sdfr		    if (nd->nd_nam2)
5489336Sdfr			nd->nd_nam = nd->nd_nam2;
5499336Sdfr		    else
5509336Sdfr			nd->nd_nam = slp->ns_nam;
5511541Srgrimes
5529336Sdfr		    /*
5539336Sdfr		     * Check to see if authorization is needed.
5549336Sdfr		     */
5559336Sdfr		    if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
5569336Sdfr			nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
5579336Sdfr			nsd->nsd_haddr = mtod(nd->nd_nam,
5589336Sdfr			    struct sockaddr_in *)->sin_addr.s_addr;
5599336Sdfr			nsd->nsd_authlen = nfsd->nfsd_authlen;
5609336Sdfr			nsd->nsd_verflen = nfsd->nfsd_verflen;
5619336Sdfr			if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
5629336Sdfr				nfsd->nfsd_authlen) &&
5639336Sdfr			    !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
5649336Sdfr				nfsd->nfsd_verflen) &&
5659336Sdfr			    !copyout((caddr_t)nsd, argp, sizeof (*nsd)))
5669336Sdfr			    return (ENEEDAUTH);
5679336Sdfr			cacherep = RC_DROPIT;
5689336Sdfr		    } else
5699336Sdfr			cacherep = nfsrv_getcache(nd, slp, &mreq);
5701541Srgrimes
5719336Sdfr		    /*
5729336Sdfr		     * Check for just starting up for NQNFS and send
5739336Sdfr		     * fake "try again later" replies to the NQNFS clients.
5749336Sdfr		     */
5759336Sdfr		    if (notstarted && nqnfsstarttime <= time.tv_sec) {
5761541Srgrimes			if (modify_flag) {
5771541Srgrimes				nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
5781541Srgrimes				modify_flag = 0;
5791541Srgrimes			} else
5801541Srgrimes				notstarted = 0;
5819336Sdfr		    }
5829336Sdfr		    if (notstarted) {
5839336Sdfr			if ((nd->nd_flag & ND_NQNFS) == 0)
5841541Srgrimes				cacherep = RC_DROPIT;
5851541Srgrimes			else if (nd->nd_procnum != NFSPROC_WRITE) {
5861541Srgrimes				nd->nd_procnum = NFSPROC_NOOP;
5871541Srgrimes				nd->nd_repstat = NQNFS_TRYLATER;
5881541Srgrimes				cacherep = RC_DOIT;
5891541Srgrimes			} else
5901541Srgrimes				modify_flag = 1;
5919336Sdfr		    } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
5929336Sdfr			nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
5931541Srgrimes			nd->nd_procnum = NFSPROC_NOOP;
5949336Sdfr			nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
5951541Srgrimes			cacherep = RC_DOIT;
5969336Sdfr		    }
5971541Srgrimes		}
5981541Srgrimes
5999336Sdfr		/*
6009336Sdfr		 * Loop to get all the write rpc relies that have been
6019336Sdfr		 * gathered together.
6029336Sdfr		 */
6039336Sdfr		do {
6049336Sdfr		    switch (cacherep) {
6059336Sdfr		    case RC_DOIT:
6069336Sdfr			if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE &&
6079336Sdfr			    nfsrvw_procrastinate > 0 && !notstarted))
6089336Sdfr			    error = nfsrv_writegather(&nd, slp,
6099336Sdfr				nfsd->nfsd_procp, &mreq);
6109336Sdfr			else
6119336Sdfr			    error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
6129336Sdfr				slp, nfsd->nfsd_procp, &mreq);
6139336Sdfr			if (mreq == NULL)
6149336Sdfr				break;
6151541Srgrimes			if (error) {
6161541Srgrimes				if (nd->nd_procnum != NQNFSPROC_VACATED)
6171541Srgrimes					nfsstats.srv_errs++;
6189336Sdfr				nfsrv_updatecache(nd, FALSE, mreq);
6199336Sdfr				if (nd->nd_nam2)
6209336Sdfr					m_freem(nd->nd_nam2);
6211541Srgrimes				break;
6221541Srgrimes			}
6231541Srgrimes			nfsstats.srvrpccnt[nd->nd_procnum]++;
6249336Sdfr			nfsrv_updatecache(nd, TRUE, mreq);
6251541Srgrimes			nd->nd_mrep = (struct mbuf *)0;
6269336Sdfr		    case RC_REPLY:
6271541Srgrimes			m = mreq;
6281541Srgrimes			siz = 0;
6291541Srgrimes			while (m) {
6301541Srgrimes				siz += m->m_len;
6311541Srgrimes				m = m->m_next;
6321541Srgrimes			}
6331541Srgrimes			if (siz <= 0 || siz > NFS_MAXPACKET) {
6341541Srgrimes				printf("mbuf siz=%d\n",siz);
6351541Srgrimes				panic("Bad nfs svc reply");
6361541Srgrimes			}
6371541Srgrimes			m = mreq;
6381541Srgrimes			m->m_pkthdr.len = siz;
6391541Srgrimes			m->m_pkthdr.rcvif = (struct ifnet *)0;
6401541Srgrimes			/*
6411541Srgrimes			 * For stream protocols, prepend a Sun RPC
6421541Srgrimes			 * Record Mark.
6431541Srgrimes			 */
6441541Srgrimes			if (sotype == SOCK_STREAM) {
6451541Srgrimes				M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
6461541Srgrimes				*mtod(m, u_long *) = htonl(0x80000000 | siz);
6471541Srgrimes			}
6481541Srgrimes			if (solockp)
6491541Srgrimes				(void) nfs_sndlock(solockp, (struct nfsreq *)0);
6501541Srgrimes			if (slp->ns_flag & SLP_VALID)
6519336Sdfr			    error = nfs_send(so, nd->nd_nam2, m, NULL);
6521541Srgrimes			else {
6531541Srgrimes			    error = EPIPE;
6541541Srgrimes			    m_freem(m);
6551541Srgrimes			}
6561541Srgrimes			if (nfsrtton)
6579336Sdfr				nfsd_rt(sotype, nd, cacherep);
6589336Sdfr			if (nd->nd_nam2)
6599336Sdfr				MFREE(nd->nd_nam2, m);
6601541Srgrimes			if (nd->nd_mrep)
6611541Srgrimes				m_freem(nd->nd_mrep);
6621541Srgrimes			if (error == EPIPE)
6631541Srgrimes				nfsrv_zapsock(slp);
6641541Srgrimes			if (solockp)
6651541Srgrimes				nfs_sndunlock(solockp);
6661541Srgrimes			if (error == EINTR || error == ERESTART) {
6679336Sdfr				free((caddr_t)nd, M_NFSRVDESC);
6681541Srgrimes				nfsrv_slpderef(slp);
6691541Srgrimes				s = splnet();
6701541Srgrimes				goto done;
6711541Srgrimes			}
6721541Srgrimes			break;
6739336Sdfr		    case RC_DROPIT:
6741541Srgrimes			if (nfsrtton)
6759336Sdfr				nfsd_rt(sotype, nd, cacherep);
6761541Srgrimes			m_freem(nd->nd_mrep);
6779336Sdfr			m_freem(nd->nd_nam2);
6781541Srgrimes			break;
6799336Sdfr		    };
6809336Sdfr		    if (nd) {
6819336Sdfr			FREE((caddr_t)nd, M_NFSRVDESC);
6829336Sdfr			nd = NULL;
6839336Sdfr		    }
6849336Sdfr
6859336Sdfr		    /*
6869336Sdfr		     * Check to see if there are outstanding writes that
6879336Sdfr		     * need to be serviced.
6889336Sdfr		     */
6899336Sdfr		    cur_usec = (u_quad_t)time.tv_sec * 1000000 +
6909336Sdfr			(u_quad_t)time.tv_usec;
6919336Sdfr		    s = splsoftclock();
6929336Sdfr		    if (slp->ns_tq.lh_first &&
6939336Sdfr			slp->ns_tq.lh_first->nd_time <= cur_usec) {
6949336Sdfr			cacherep = RC_DOIT;
6959336Sdfr			writes_todo = 1;
6969336Sdfr		    } else
6979336Sdfr			writes_todo = 0;
6989336Sdfr		    splx(s);
6999336Sdfr		} while (writes_todo);
7001541Srgrimes		s = splnet();
7019336Sdfr		if (nfsrv_dorec(slp, nfsd, &nd)) {
7029336Sdfr			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
7039336Sdfr			nfsd->nfsd_slp = NULL;
7041541Srgrimes			nfsrv_slpderef(slp);
7051541Srgrimes		}
7061541Srgrimes	}
7071541Srgrimesdone:
7089336Sdfr	TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
7091541Srgrimes	splx(s);
7109336Sdfr	free((caddr_t)nfsd, M_NFSD);
7111541Srgrimes	nsd->nsd_nfsd = (struct nfsd *)0;
7121541Srgrimes	if (--nfs_numnfsd == 0)
7131541Srgrimes		nfsrv_init(TRUE);	/* Reinitialize everything */
7141541Srgrimes	return (error);
7151541Srgrimes}
71613416Sphk#endif /* NFS_NOSERVER */
7171541Srgrimes
71819449Sdfrint nfs_defect = 0;
71919449SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, "");
72019449Sdfr
7211541Srgrimes/*
7221541Srgrimes * Asynchronous I/O daemons for client nfs.
7231541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache.
7241541Srgrimes * Never returns unless it fails or gets killed.
7251541Srgrimes */
72612911Sphkstatic int
7271541Srgrimesnfssvc_iod(p)
7281541Srgrimes	struct proc *p;
7291541Srgrimes{
7309336Sdfr	register struct buf *bp, *nbp;
7311541Srgrimes	register int i, myiod;
7329336Sdfr	struct vnode *vp;
73319449Sdfr	struct nfsmount *nmp;
7349336Sdfr	int error = 0, s;
7351541Srgrimes
7361541Srgrimes	/*
7371541Srgrimes	 * Assign my position or return error if too many already running
7381541Srgrimes	 */
7391541Srgrimes	myiod = -1;
7401541Srgrimes	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
7411541Srgrimes		if (nfs_asyncdaemon[i] == 0) {
7421541Srgrimes			nfs_asyncdaemon[i]++;
7431541Srgrimes			myiod = i;
7441541Srgrimes			break;
7451541Srgrimes		}
7461541Srgrimes	if (myiod == -1)
7471541Srgrimes		return (EBUSY);
7481541Srgrimes	nfs_numasync++;
7491541Srgrimes	/*
7501541Srgrimes	 * Just loop around doin our stuff until SIGKILL
7511541Srgrimes	 */
7521541Srgrimes	for (;;) {
75319449Sdfr	    while (((nmp = nfs_iodmount[myiod]) == NULL
75419449Sdfr		    || nmp->nm_bufq.tqh_first == NULL)
75519449Sdfr		   && error == 0) {
75619449Sdfr		if (nmp)
75719449Sdfr		    nmp->nm_bufqiods--;
7589336Sdfr		nfs_iodwant[myiod] = p;
75919449Sdfr		nfs_iodmount[myiod] = NULL;
7609336Sdfr		error = tsleep((caddr_t)&nfs_iodwant[myiod],
7619336Sdfr			PWAIT | PCATCH, "nfsidl", 0);
7629336Sdfr	    }
76319449Sdfr	    if (error) {
76419449Sdfr		nfs_asyncdaemon[myiod] = 0;
76519449Sdfr		if (nmp) nmp->nm_bufqiods--;
76619449Sdfr		nfs_iodmount[myiod] = NULL;
76719449Sdfr		nfs_numasync--;
76819449Sdfr		return (error);
76919449Sdfr	    }
77019449Sdfr	    while ((bp = nmp->nm_bufq.tqh_first) != NULL) {
7719336Sdfr		/* Take one off the front of the list */
77219449Sdfr		TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
77319449Sdfr		nmp->nm_bufqlen--;
77419449Sdfr		if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) {
77519449Sdfr		    nmp->nm_bufqwant = FALSE;
77619449Sdfr		    wakeup(&nmp->nm_bufq);
77719449Sdfr		}
7789336Sdfr		if (bp->b_flags & B_READ)
7799336Sdfr		    (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
78019449Sdfr		else
7819336Sdfr		    (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
78219449Sdfr
78319449Sdfr		/*
78419449Sdfr		 * If there are more than one iod on this mount, then defect
78519449Sdfr		 * so that the iods can be shared out fairly between the mounts
78619449Sdfr		 */
78719449Sdfr		if (nfs_defect && nmp->nm_bufqiods > 1) {
78819449Sdfr		    NFS_DPF(ASYNCIO,
78919449Sdfr			    ("nfssvc_iod: iod %d defecting from mount %p\n",
79019449Sdfr			     myiod, nmp));
79119449Sdfr		    nfs_iodmount[myiod] = NULL;
79219449Sdfr		    nmp->nm_bufqiods--;
79319449Sdfr		    break;
79419449Sdfr		}
7959336Sdfr	    }
7961541Srgrimes	}
7971541Srgrimes}
7981541Srgrimes
7991541Srgrimes/*
8001541Srgrimes * Shut down a socket associated with an nfssvc_sock structure.
8011541Srgrimes * Should be called with the send lock set, if required.
8021541Srgrimes * The trick here is to increment the sref at the start, so that the nfsds
8031541Srgrimes * will stop using it and clear ns_flag at the end so that it will not be
8041541Srgrimes * reassigned during cleanup.
8051541Srgrimes */
80612911Sphkstatic void
8071541Srgrimesnfsrv_zapsock(slp)
8081541Srgrimes	register struct nfssvc_sock *slp;
8091541Srgrimes{
8103664Sphk	register struct nfsuid *nuidp, *nnuidp;
8119336Sdfr	register struct nfsrv_descript *nwp, *nnwp;
8121541Srgrimes	struct socket *so;
8131541Srgrimes	struct file *fp;
8141541Srgrimes	struct mbuf *m;
8159336Sdfr	int s;
8161541Srgrimes
8171541Srgrimes	slp->ns_flag &= ~SLP_ALLFLAGS;
8183305Sphk	fp = slp->ns_fp;
8193305Sphk	if (fp) {
8201541Srgrimes		slp->ns_fp = (struct file *)0;
8211541Srgrimes		so = slp->ns_so;
8221541Srgrimes		so->so_upcall = NULL;
8231541Srgrimes		soshutdown(so, 2);
8241541Srgrimes		closef(fp, (struct proc *)0);
8251541Srgrimes		if (slp->ns_nam)
8261541Srgrimes			MFREE(slp->ns_nam, m);
8271541Srgrimes		m_freem(slp->ns_raw);
8281541Srgrimes		m_freem(slp->ns_rec);
8293664Sphk		for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0;
8303664Sphk		    nuidp = nnuidp) {
8313664Sphk			nnuidp = nuidp->nu_lru.tqe_next;
8323664Sphk			LIST_REMOVE(nuidp, nu_hash);
8333664Sphk			TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
8349336Sdfr			if (nuidp->nu_flag & NU_NAM)
8359336Sdfr				m_freem(nuidp->nu_nam);
8363664Sphk			free((caddr_t)nuidp, M_NFSUID);
8371541Srgrimes		}
8389336Sdfr		s = splsoftclock();
8399336Sdfr		for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
8409336Sdfr			nnwp = nwp->nd_tq.le_next;
8419336Sdfr			LIST_REMOVE(nwp, nd_tq);
8429336Sdfr			free((caddr_t)nwp, M_NFSRVDESC);
8439336Sdfr		}
8449336Sdfr		LIST_INIT(&slp->ns_tq);
8459336Sdfr		splx(s);
8461541Srgrimes	}
8471541Srgrimes}
8481541Srgrimes
8491541Srgrimes/*
8501541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting
8511541Srgrimes * on this mount point porpous out of the kernel and do it.
8521541Srgrimes */
8531549Srgrimesint
8549336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
8551541Srgrimes	register struct nfsmount *nmp;
8561541Srgrimes	struct nfsreq *rep;
8571541Srgrimes	struct ucred *cred;
8581541Srgrimes	char **auth_str;
8591541Srgrimes	int *auth_len;
8609336Sdfr	char *verf_str;
8619336Sdfr	int *verf_len;
8629336Sdfr	NFSKERBKEY_T key;		/* return session key */
8631541Srgrimes{
8641541Srgrimes	int error = 0;
8651541Srgrimes
8661541Srgrimes	while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
8671541Srgrimes		nmp->nm_flag |= NFSMNT_WANTAUTH;
8681541Srgrimes		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
8691541Srgrimes			"nfsauth1", 2 * hz);
8703305Sphk		error = nfs_sigintr(nmp, rep, rep->r_procp);
8713305Sphk		if (error) {
8721541Srgrimes			nmp->nm_flag &= ~NFSMNT_WANTAUTH;
8731541Srgrimes			return (error);
8741541Srgrimes		}
8751541Srgrimes	}
8761541Srgrimes	nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
8771541Srgrimes	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
8789336Sdfr	nmp->nm_authlen = RPCAUTH_MAXSIZ;
8799336Sdfr	nmp->nm_verfstr = verf_str;
8809336Sdfr	nmp->nm_verflen = *verf_len;
8811541Srgrimes	nmp->nm_authuid = cred->cr_uid;
8821541Srgrimes	wakeup((caddr_t)&nmp->nm_authstr);
8831541Srgrimes
8841541Srgrimes	/*
8851541Srgrimes	 * And wait for mount_nfs to do its stuff.
8861541Srgrimes	 */
8871541Srgrimes	while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
8881541Srgrimes		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
8891541Srgrimes			"nfsauth2", 2 * hz);
8901541Srgrimes		error = nfs_sigintr(nmp, rep, rep->r_procp);
8911541Srgrimes	}
8921541Srgrimes	if (nmp->nm_flag & NFSMNT_AUTHERR) {
8931541Srgrimes		nmp->nm_flag &= ~NFSMNT_AUTHERR;
8941541Srgrimes		error = EAUTH;
8951541Srgrimes	}
8961541Srgrimes	if (error)
8971541Srgrimes		free((caddr_t)*auth_str, M_TEMP);
8981541Srgrimes	else {
8991541Srgrimes		*auth_len = nmp->nm_authlen;
9009336Sdfr		*verf_len = nmp->nm_verflen;
9019336Sdfr		bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
9021541Srgrimes	}
9031541Srgrimes	nmp->nm_flag &= ~NFSMNT_HASAUTH;
9041541Srgrimes	nmp->nm_flag |= NFSMNT_WAITAUTH;
9051541Srgrimes	if (nmp->nm_flag & NFSMNT_WANTAUTH) {
9061541Srgrimes		nmp->nm_flag &= ~NFSMNT_WANTAUTH;
9071541Srgrimes		wakeup((caddr_t)&nmp->nm_authtype);
9081541Srgrimes	}
9091541Srgrimes	return (error);
9101541Srgrimes}
9111541Srgrimes
9121541Srgrimes/*
9139336Sdfr * Get a nickname authenticator and verifier.
9149336Sdfr */
9159336Sdfrint
9169336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
9179336Sdfr	struct nfsmount *nmp;
9189336Sdfr	struct ucred *cred;
9199336Sdfr	char **auth_str;
9209336Sdfr	int *auth_len;
9219336Sdfr	char *verf_str;
9229336Sdfr	int verf_len;
9239336Sdfr{
9249336Sdfr	register struct nfsuid *nuidp;
9259336Sdfr	register u_long *nickp, *verfp;
9269336Sdfr	struct timeval ktvin, ktvout;
9279336Sdfr
9289336Sdfr#ifdef DIAGNOSTIC
9299336Sdfr	if (verf_len < (4 * NFSX_UNSIGNED))
9309336Sdfr		panic("nfs_getnickauth verf too small");
9319336Sdfr#endif
9329336Sdfr	for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
9339336Sdfr	    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
9349336Sdfr		if (nuidp->nu_cr.cr_uid == cred->cr_uid)
9359336Sdfr			break;
9369336Sdfr	}
9379336Sdfr	if (!nuidp || nuidp->nu_expire < time.tv_sec)
9389336Sdfr		return (EACCES);
9399336Sdfr
9409336Sdfr	/*
9419336Sdfr	 * Move to the end of the lru list (end of lru == most recently used).
9429336Sdfr	 */
9439336Sdfr	TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
9449336Sdfr	TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
9459336Sdfr
9469336Sdfr	nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
9479336Sdfr	*nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
9489336Sdfr	*nickp = txdr_unsigned(nuidp->nu_nickname);
9499336Sdfr	*auth_str = (char *)nickp;
9509336Sdfr	*auth_len = 2 * NFSX_UNSIGNED;
9519336Sdfr
9529336Sdfr	/*
9539336Sdfr	 * Now we must encrypt the verifier and package it up.
9549336Sdfr	 */
9559336Sdfr	verfp = (u_long *)verf_str;
9569336Sdfr	*verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
9579336Sdfr	if (time.tv_sec > nuidp->nu_timestamp.tv_sec ||
9589336Sdfr	    (time.tv_sec == nuidp->nu_timestamp.tv_sec &&
9599336Sdfr	     time.tv_usec > nuidp->nu_timestamp.tv_usec))
9609336Sdfr		nuidp->nu_timestamp = time;
9619336Sdfr	else
9629336Sdfr		nuidp->nu_timestamp.tv_usec++;
9639336Sdfr	ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
9649336Sdfr	ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
9659336Sdfr
9669336Sdfr	/*
9679336Sdfr	 * Now encrypt the timestamp verifier in ecb mode using the session
9689336Sdfr	 * key.
9699336Sdfr	 */
9709336Sdfr#ifdef NFSKERB
9719336Sdfr	XXX
9729336Sdfr#endif
9739336Sdfr
9749336Sdfr	*verfp++ = ktvout.tv_sec;
9759336Sdfr	*verfp++ = ktvout.tv_usec;
9769336Sdfr	*verfp = 0;
9779336Sdfr	return (0);
9789336Sdfr}
9799336Sdfr
9809336Sdfr/*
9819336Sdfr * Save the current nickname in a hash list entry on the mount point.
9829336Sdfr */
9839336Sdfrint
9849336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
9859336Sdfr	register struct nfsmount *nmp;
9869336Sdfr	struct ucred *cred;
9879336Sdfr	int len;
9889336Sdfr	NFSKERBKEY_T key;
9899336Sdfr	struct mbuf **mdp;
9909336Sdfr	char **dposp;
9919336Sdfr	struct mbuf *mrep;
9929336Sdfr{
9939336Sdfr	register struct nfsuid *nuidp;
9949336Sdfr	register u_long *tl;
9959336Sdfr	register long t1;
9969336Sdfr	struct mbuf *md = *mdp;
9979336Sdfr	struct timeval ktvin, ktvout;
9989336Sdfr	u_long nick;
9999336Sdfr	char *dpos = *dposp, *cp2;
10009336Sdfr	int deltasec, error = 0;
10019336Sdfr
10029336Sdfr	if (len == (3 * NFSX_UNSIGNED)) {
10039336Sdfr		nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
10049336Sdfr		ktvin.tv_sec = *tl++;
10059336Sdfr		ktvin.tv_usec = *tl++;
10069336Sdfr		nick = fxdr_unsigned(u_long, *tl);
10079336Sdfr
10089336Sdfr		/*
10099336Sdfr		 * Decrypt the timestamp in ecb mode.
10109336Sdfr		 */
10119336Sdfr#ifdef NFSKERB
10129336Sdfr		XXX
10139336Sdfr#endif
10149336Sdfr		ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
10159336Sdfr		ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
10169336Sdfr		deltasec = time.tv_sec - ktvout.tv_sec;
10179336Sdfr		if (deltasec < 0)
10189336Sdfr			deltasec = -deltasec;
10199336Sdfr		/*
10209336Sdfr		 * If ok, add it to the hash list for the mount point.
10219336Sdfr		 */
10229336Sdfr		if (deltasec <= NFS_KERBCLOCKSKEW) {
10239336Sdfr			if (nmp->nm_numuids < nuidhash_max) {
10249336Sdfr				nmp->nm_numuids++;
10259336Sdfr				nuidp = (struct nfsuid *)
10269336Sdfr				   malloc(sizeof (struct nfsuid), M_NFSUID,
10279336Sdfr					M_WAITOK);
10289336Sdfr			} else {
10299336Sdfr				nuidp = nmp->nm_uidlruhead.tqh_first;
10309336Sdfr				LIST_REMOVE(nuidp, nu_hash);
10319336Sdfr				TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
10329336Sdfr					nu_lru);
10339336Sdfr			}
10349336Sdfr			nuidp->nu_flag = 0;
10359336Sdfr			nuidp->nu_cr.cr_uid = cred->cr_uid;
10369336Sdfr			nuidp->nu_expire = time.tv_sec + NFS_KERBTTL;
10379336Sdfr			nuidp->nu_timestamp = ktvout;
10389336Sdfr			nuidp->nu_nickname = nick;
10399336Sdfr			bcopy(key, nuidp->nu_key, sizeof (key));
10409336Sdfr			TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
10419336Sdfr				nu_lru);
10429336Sdfr			LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
10439336Sdfr				nuidp, nu_hash);
10449336Sdfr		}
10459336Sdfr	} else
10469336Sdfr		nfsm_adv(nfsm_rndup(len));
10479336Sdfrnfsmout:
10489336Sdfr	*mdp = md;
10499336Sdfr	*dposp = dpos;
10509336Sdfr	return (error);
10519336Sdfr}
10529336Sdfr
105313416Sphk#ifndef NFS_NOSERVER
10549336Sdfr/*
10551541Srgrimes * Derefence a server socket structure. If it has no more references and
10561541Srgrimes * is no longer valid, you can throw it away.
10571541Srgrimes */
10581541Srgrimesvoid
10591541Srgrimesnfsrv_slpderef(slp)
10601541Srgrimes	register struct nfssvc_sock *slp;
10611541Srgrimes{
10621541Srgrimes	if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
10633664Sphk		TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
10641541Srgrimes		free((caddr_t)slp, M_NFSSVC);
10651541Srgrimes	}
10661541Srgrimes}
10671541Srgrimes
10681541Srgrimes/*
10691541Srgrimes * Initialize the data structures for the server.
10701541Srgrimes * Handshake with any new nfsds starting up to avoid any chance of
10711541Srgrimes * corruption.
10721541Srgrimes */
10731541Srgrimesvoid
10741541Srgrimesnfsrv_init(terminating)
10751541Srgrimes	int terminating;
10761541Srgrimes{
10773664Sphk	register struct nfssvc_sock *slp, *nslp;
10781541Srgrimes
10793664Sphk	if (nfssvc_sockhead_flag & SLP_INIT)
10801541Srgrimes		panic("nfsd init");
10813664Sphk	nfssvc_sockhead_flag |= SLP_INIT;
10821541Srgrimes	if (terminating) {
10833664Sphk		for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) {
10843664Sphk			nslp = slp->ns_chain.tqe_next;
10851541Srgrimes			if (slp->ns_flag & SLP_VALID)
10861541Srgrimes				nfsrv_zapsock(slp);
10873664Sphk			TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
10883664Sphk			free((caddr_t)slp, M_NFSSVC);
10891541Srgrimes		}
10901541Srgrimes		nfsrv_cleancache();	/* And clear out server cache */
10911541Srgrimes	}
10923664Sphk
10933664Sphk	TAILQ_INIT(&nfssvc_sockhead);
10943664Sphk	nfssvc_sockhead_flag &= ~SLP_INIT;
10953664Sphk	if (nfssvc_sockhead_flag & SLP_WANTINIT) {
10963664Sphk		nfssvc_sockhead_flag &= ~SLP_WANTINIT;
10973664Sphk		wakeup((caddr_t)&nfssvc_sockhead);
10983664Sphk	}
10993664Sphk
11003664Sphk	TAILQ_INIT(&nfsd_head);
11013664Sphk	nfsd_head_flag &= ~NFSD_CHECKSLP;
11023664Sphk
11031541Srgrimes	nfs_udpsock = (struct nfssvc_sock *)
11041541Srgrimes	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
11051541Srgrimes	bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
11063664Sphk	TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
11073664Sphk	TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
11083664Sphk
11091541Srgrimes	nfs_cltpsock = (struct nfssvc_sock *)
11101541Srgrimes	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
11111541Srgrimes	bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
11123664Sphk	TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
11133664Sphk	TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
11141541Srgrimes}
11151541Srgrimes
11161541Srgrimes/*
11171541Srgrimes * Add entries to the server monitor log.
11181541Srgrimes */
11191541Srgrimesstatic void
11209336Sdfrnfsd_rt(sotype, nd, cacherep)
11211541Srgrimes	int sotype;
11229336Sdfr	register struct nfsrv_descript *nd;
11231541Srgrimes	int cacherep;
11241541Srgrimes{
11251541Srgrimes	register struct drt *rt;
11261541Srgrimes
11271541Srgrimes	rt = &nfsdrt.drt[nfsdrt.pos];
11281541Srgrimes	if (cacherep == RC_DOIT)
11291541Srgrimes		rt->flag = 0;
11301541Srgrimes	else if (cacherep == RC_REPLY)
11311541Srgrimes		rt->flag = DRT_CACHEREPLY;
11321541Srgrimes	else
11331541Srgrimes		rt->flag = DRT_CACHEDROP;
11341541Srgrimes	if (sotype == SOCK_STREAM)
11351541Srgrimes		rt->flag |= DRT_TCP;
11369336Sdfr	if (nd->nd_flag & ND_NQNFS)
11371541Srgrimes		rt->flag |= DRT_NQNFS;
11389336Sdfr	else if (nd->nd_flag & ND_NFSV3)
11399336Sdfr		rt->flag |= DRT_NFSV3;
11401541Srgrimes	rt->proc = nd->nd_procnum;
11419336Sdfr	if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET)
11429336Sdfr	    rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr;
11431541Srgrimes	else
11449336Sdfr	    rt->ipadr = INADDR_ANY;
11459336Sdfr	rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
11469336Sdfr		(time.tv_usec - nd->nd_starttime.tv_usec);
11471541Srgrimes	rt->tstamp = time;
11481541Srgrimes	nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
11491541Srgrimes}
115013416Sphk#endif /* NFS_NOSERVER */
1151