nfs_nfsiod.c revision 22521
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 *
3622521Sdyson *	@(#)nfs_syscalls.c	8.5 (Berkeley) 3/30/95
3721673Sjkh * $FreeBSD: head/sys/nfsclient/nfs_nfsiod.c 22521 1997-02-10 02:22:35Z dyson $
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#ifndef NFS_NOSERVER
10113416Sphkint nfsd_waiting = 0;
10213416Sphkstatic struct nfsdrt nfsdrt;
10313416Sphkstatic int nfs_numnfsd = 0;
10413416Sphkstatic int notstarted = 1;
10513416Sphkstatic int modify_flag = 0;
10612457Sbdestatic void	nfsd_rt __P((int sotype, struct nfsrv_descript *nd,
10712457Sbde			     int cacherep));
10812911Sphkstatic int	nfssvc_addsock __P((struct file *,struct mbuf *));
10912911Sphkstatic int	nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *));
1101541Srgrimes/*
1111541Srgrimes * NFS server system calls
1121541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
1131541Srgrimes */
1141541Srgrimes
1151541Srgrimes/*
1161541Srgrimes * Get file handle system call
1171541Srgrimes */
11812274Sbde#ifndef _SYS_SYSPROTO_H_
1191541Srgrimesstruct getfh_args {
1201541Srgrimes	char	*fname;
1211541Srgrimes	fhandle_t *fhp;
1221541Srgrimes};
12312274Sbde#endif
1241549Srgrimesint
1251541Srgrimesgetfh(p, uap, retval)
1261541Srgrimes	struct proc *p;
1271541Srgrimes	register struct getfh_args *uap;
1281541Srgrimes	int *retval;
1291541Srgrimes{
1301541Srgrimes	register struct vnode *vp;
1311541Srgrimes	fhandle_t fh;
1321541Srgrimes	int error;
1331541Srgrimes	struct nameidata nd;
1341541Srgrimes
1351541Srgrimes	/*
1361541Srgrimes	 * Must be super user
1371541Srgrimes	 */
1383305Sphk	error = suser(p->p_ucred, &p->p_acflag);
1393305Sphk	if(error)
1401541Srgrimes		return (error);
1411541Srgrimes	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1423305Sphk	error = namei(&nd);
1433305Sphk	if (error)
1441541Srgrimes		return (error);
1451541Srgrimes	vp = nd.ni_vp;
1461541Srgrimes	bzero((caddr_t)&fh, sizeof(fh));
1471541Srgrimes	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1481541Srgrimes	error = VFS_VPTOFH(vp, &fh.fh_fid);
1491541Srgrimes	vput(vp);
1501541Srgrimes	if (error)
1511541Srgrimes		return (error);
1521541Srgrimes	error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
1531541Srgrimes	return (error);
1541541Srgrimes}
1551541Srgrimes
15613416Sphk#endif /* NFS_NOSERVER */
1571541Srgrimes/*
1581541Srgrimes * Nfs server psuedo system call for the nfsd's
1591541Srgrimes * Based on the flag value it either:
1601541Srgrimes * - adds a socket to the selection list
1611541Srgrimes * - remains in the kernel as an nfsd
1621541Srgrimes * - remains in the kernel as an nfsiod
1631541Srgrimes */
16412274Sbde#ifndef _SYS_SYSPROTO_H_
1651541Srgrimesstruct nfssvc_args {
1661541Srgrimes	int flag;
1671541Srgrimes	caddr_t argp;
1681541Srgrimes};
16912274Sbde#endif
1701549Srgrimesint
1711541Srgrimesnfssvc(p, uap, retval)
1721541Srgrimes	struct proc *p;
1731541Srgrimes	register struct nfssvc_args *uap;
1741541Srgrimes	int *retval;
1751541Srgrimes{
17613416Sphk#ifndef NFS_NOSERVER
1771541Srgrimes	struct nameidata nd;
1781541Srgrimes	struct file *fp;
1791541Srgrimes	struct mbuf *nam;
1801541Srgrimes	struct nfsd_args nfsdarg;
1811541Srgrimes	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
1821541Srgrimes	struct nfsd_cargs ncd;
1831541Srgrimes	struct nfsd *nfsd;
1841541Srgrimes	struct nfssvc_sock *slp;
1853664Sphk	struct nfsuid *nuidp;
1861541Srgrimes	struct nfsmount *nmp;
18713416Sphk#endif /* NFS_NOSERVER */
1881541Srgrimes	int error;
1891541Srgrimes
1901541Srgrimes	/*
1911541Srgrimes	 * Must be super user
1921541Srgrimes	 */
1933305Sphk	error = suser(p->p_ucred, &p->p_acflag);
1943305Sphk	if(error)
1951541Srgrimes		return (error);
1963664Sphk	while (nfssvc_sockhead_flag & SLP_INIT) {
1973664Sphk		 nfssvc_sockhead_flag |= SLP_WANTINIT;
1981541Srgrimes		(void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
1991541Srgrimes	}
2001541Srgrimes	if (uap->flag & NFSSVC_BIOD)
2011541Srgrimes		error = nfssvc_iod(p);
20213416Sphk#ifdef NFS_NOSERVER
20313416Sphk	else
20413416Sphk		error = ENXIO;
20513416Sphk#else /* !NFS_NOSERVER */
2061541Srgrimes	else if (uap->flag & NFSSVC_MNTD) {
2073305Sphk		error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd));
2083305Sphk		if (error)
2091541Srgrimes			return (error);
2101541Srgrimes		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2111541Srgrimes			ncd.ncd_dirp, p);
2123305Sphk		error = namei(&nd);
2133305Sphk		if (error)
2141541Srgrimes			return (error);
2151541Srgrimes		if ((nd.ni_vp->v_flag & VROOT) == 0)
2161541Srgrimes			error = EINVAL;
2171541Srgrimes		nmp = VFSTONFS(nd.ni_vp->v_mount);
2181541Srgrimes		vput(nd.ni_vp);
2191541Srgrimes		if (error)
2201541Srgrimes			return (error);
2211541Srgrimes		if ((nmp->nm_flag & NFSMNT_MNTD) &&
2221541Srgrimes			(uap->flag & NFSSVC_GOTAUTH) == 0)
2231541Srgrimes			return (0);
2241541Srgrimes		nmp->nm_flag |= NFSMNT_MNTD;
2251541Srgrimes		error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
2261541Srgrimes			uap->argp, p);
2271541Srgrimes	} else if (uap->flag & NFSSVC_ADDSOCK) {
2283305Sphk		error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
2293305Sphk		if (error)
2301541Srgrimes			return (error);
2313305Sphk		error = getsock(p->p_fd, nfsdarg.sock, &fp);
2323305Sphk		if (error)
2331541Srgrimes			return (error);
2341541Srgrimes		/*
2351541Srgrimes		 * Get the client address for connected sockets.
2361541Srgrimes		 */
2371541Srgrimes		if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
2381541Srgrimes			nam = (struct mbuf *)0;
2393305Sphk		else {
2403305Sphk			error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
2413305Sphk				MT_SONAME);
2423305Sphk			if (error)
2433305Sphk				return (error);
2443305Sphk		}
2451541Srgrimes		error = nfssvc_addsock(fp, nam);
2461541Srgrimes	} else {
2473305Sphk		error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd));
2483305Sphk		if (error)
2491541Srgrimes			return (error);
2503305Sphk		if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) &&
2519336Sdfr			(nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
2529336Sdfr			slp = nfsd->nfsd_slp;
2531541Srgrimes
2541541Srgrimes			/*
2551541Srgrimes			 * First check to see if another nfsd has already
2561541Srgrimes			 * added this credential.
2571541Srgrimes			 */
2589336Sdfr			for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
2593664Sphk			    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
2609336Sdfr				if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
2619336Sdfr				    (!nfsd->nfsd_nd->nd_nam2 ||
2629336Sdfr				     netaddr_match(NU_NETFAM(nuidp),
2639336Sdfr				     &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
2641541Srgrimes					break;
2651541Srgrimes			}
2669336Sdfr			if (nuidp) {
2679336Sdfr			    nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
2689336Sdfr			    nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
2699336Sdfr			} else {
2701541Srgrimes			    /*
2711541Srgrimes			     * Nope, so we will.
2721541Srgrimes			     */
2731541Srgrimes			    if (slp->ns_numuids < nuidhash_max) {
2741541Srgrimes				slp->ns_numuids++;
2751541Srgrimes				nuidp = (struct nfsuid *)
2761541Srgrimes				   malloc(sizeof (struct nfsuid), M_NFSUID,
2771541Srgrimes					M_WAITOK);
2781541Srgrimes			    } else
2791541Srgrimes				nuidp = (struct nfsuid *)0;
2801541Srgrimes			    if ((slp->ns_flag & SLP_VALID) == 0) {
2811541Srgrimes				if (nuidp)
2821541Srgrimes				    free((caddr_t)nuidp, M_NFSUID);
2831541Srgrimes			    } else {
2841541Srgrimes				if (nuidp == (struct nfsuid *)0) {
2853664Sphk				    nuidp = slp->ns_uidlruhead.tqh_first;
2863664Sphk				    LIST_REMOVE(nuidp, nu_hash);
2873664Sphk				    TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
2883664Sphk					nu_lru);
2899336Sdfr				    if (nuidp->nu_flag & NU_NAM)
2909336Sdfr					m_freem(nuidp->nu_nam);
2911541Srgrimes			        }
2929336Sdfr				nuidp->nu_flag = 0;
2931541Srgrimes				nuidp->nu_cr = nsd->nsd_cr;
2941541Srgrimes				if (nuidp->nu_cr.cr_ngroups > NGROUPS)
2959336Sdfr				    nuidp->nu_cr.cr_ngroups = NGROUPS;
2961541Srgrimes				nuidp->nu_cr.cr_ref = 1;
2979336Sdfr				nuidp->nu_timestamp = nsd->nsd_timestamp;
2989336Sdfr				nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl;
2999336Sdfr				/*
3009336Sdfr				 * and save the session key in nu_key.
3019336Sdfr				 */
3029336Sdfr				bcopy(nsd->nsd_key, nuidp->nu_key,
3039336Sdfr				    sizeof (nsd->nsd_key));
3049336Sdfr				if (nfsd->nfsd_nd->nd_nam2) {
3059336Sdfr				    struct sockaddr_in *saddr;
3069336Sdfr
3079336Sdfr				    saddr = mtod(nfsd->nfsd_nd->nd_nam2,
3089336Sdfr					 struct sockaddr_in *);
3099336Sdfr				    switch (saddr->sin_family) {
3109336Sdfr				    case AF_INET:
3119336Sdfr					nuidp->nu_flag |= NU_INETADDR;
3129336Sdfr					nuidp->nu_inetaddr =
3139336Sdfr					     saddr->sin_addr.s_addr;
3149336Sdfr					break;
3159336Sdfr				    case AF_ISO:
3169336Sdfr				    default:
3179336Sdfr					nuidp->nu_flag |= NU_NAM;
3189336Sdfr					nuidp->nu_nam = m_copym(
3199336Sdfr					    nfsd->nfsd_nd->nd_nam2, 0,
3209336Sdfr					     M_COPYALL, M_WAIT);
3219336Sdfr					break;
3229336Sdfr				    };
3239336Sdfr				}
3243664Sphk				TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
3253664Sphk					nu_lru);
3263664Sphk				LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
3273664Sphk					nuidp, nu_hash);
3289336Sdfr				nfsrv_setcred(&nuidp->nu_cr,
3299336Sdfr				    &nfsd->nfsd_nd->nd_cr);
3309336Sdfr				nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
3311541Srgrimes			    }
3321541Srgrimes			}
3331541Srgrimes		}
3341541Srgrimes		if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
3359336Sdfr			nfsd->nfsd_flag |= NFSD_AUTHFAIL;
3361541Srgrimes		error = nfssvc_nfsd(nsd, uap->argp, p);
3371541Srgrimes	}
33813416Sphk#endif /* NFS_NOSERVER */
3391541Srgrimes	if (error == EINTR || error == ERESTART)
3401541Srgrimes		error = 0;
3411541Srgrimes	return (error);
3421541Srgrimes}
3431541Srgrimes
34413416Sphk#ifndef NFS_NOSERVER
3451541Srgrimes/*
3461541Srgrimes * Adds a socket to the list for servicing by nfsds.
3471541Srgrimes */
34812911Sphkstatic int
3491541Srgrimesnfssvc_addsock(fp, mynam)
3501541Srgrimes	struct file *fp;
3511541Srgrimes	struct mbuf *mynam;
3521541Srgrimes{
3531541Srgrimes	register struct mbuf *m;
3541541Srgrimes	register int siz;
3551541Srgrimes	register struct nfssvc_sock *slp;
3561541Srgrimes	register struct socket *so;
3571541Srgrimes	struct nfssvc_sock *tslp;
3581541Srgrimes	int error, s;
3591541Srgrimes
3601541Srgrimes	so = (struct socket *)fp->f_data;
3611541Srgrimes	tslp = (struct nfssvc_sock *)0;
3621541Srgrimes	/*
3631541Srgrimes	 * Add it to the list, as required.
3641541Srgrimes	 */
3651541Srgrimes	if (so->so_proto->pr_protocol == IPPROTO_UDP) {
3661541Srgrimes		tslp = nfs_udpsock;
3671541Srgrimes		if (tslp->ns_flag & SLP_VALID) {
3681541Srgrimes			m_freem(mynam);
3691541Srgrimes			return (EPERM);
3701541Srgrimes		}
3711541Srgrimes#ifdef ISO
3721541Srgrimes	} else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
3731541Srgrimes		tslp = nfs_cltpsock;
3741541Srgrimes		if (tslp->ns_flag & SLP_VALID) {
3751541Srgrimes			m_freem(mynam);
3761541Srgrimes			return (EPERM);
3771541Srgrimes		}
3781541Srgrimes#endif /* ISO */
3791541Srgrimes	}
3801541Srgrimes	if (so->so_type == SOCK_STREAM)
3811541Srgrimes		siz = NFS_MAXPACKET + sizeof (u_long);
3821541Srgrimes	else
3831541Srgrimes		siz = NFS_MAXPACKET;
3848876Srgrimes	error = soreserve(so, siz, siz);
3853305Sphk	if (error) {
3861541Srgrimes		m_freem(mynam);
3871541Srgrimes		return (error);
3881541Srgrimes	}
3891541Srgrimes
3901541Srgrimes	/*
3911541Srgrimes	 * Set protocol specific options { for now TCP only } and
3921541Srgrimes	 * reserve some space. For datagram sockets, this can get called
3931541Srgrimes	 * repeatedly for the same socket, but that isn't harmful.
3941541Srgrimes	 */
3951541Srgrimes	if (so->so_type == SOCK_STREAM) {
3961541Srgrimes		MGET(m, M_WAIT, MT_SOOPTS);
3971541Srgrimes		*mtod(m, int *) = 1;
3981541Srgrimes		m->m_len = sizeof(int);
3991541Srgrimes		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
4001541Srgrimes	}
4011541Srgrimes	if (so->so_proto->pr_domain->dom_family == AF_INET &&
4021541Srgrimes	    so->so_proto->pr_protocol == IPPROTO_TCP) {
4031541Srgrimes		MGET(m, M_WAIT, MT_SOOPTS);
4041541Srgrimes		*mtod(m, int *) = 1;
4051541Srgrimes		m->m_len = sizeof(int);
4061541Srgrimes		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
4071541Srgrimes	}
4081541Srgrimes	so->so_rcv.sb_flags &= ~SB_NOINTR;
4091541Srgrimes	so->so_rcv.sb_timeo = 0;
4101541Srgrimes	so->so_snd.sb_flags &= ~SB_NOINTR;
4111541Srgrimes	so->so_snd.sb_timeo = 0;
4121541Srgrimes	if (tslp)
4131541Srgrimes		slp = tslp;
4141541Srgrimes	else {
4151541Srgrimes		slp = (struct nfssvc_sock *)
4161541Srgrimes			malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
4171541Srgrimes		bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
4183664Sphk		TAILQ_INIT(&slp->ns_uidlruhead);
4193664Sphk		TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
4201541Srgrimes	}
4211541Srgrimes	slp->ns_so = so;
4221541Srgrimes	slp->ns_nam = mynam;
4231541Srgrimes	fp->f_count++;
4241541Srgrimes	slp->ns_fp = fp;
4251541Srgrimes	s = splnet();
4261541Srgrimes	so->so_upcallarg = (caddr_t)slp;
4271541Srgrimes	so->so_upcall = nfsrv_rcv;
4281541Srgrimes	slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
4291541Srgrimes	nfsrv_wakenfsd(slp);
4301541Srgrimes	splx(s);
4311541Srgrimes	return (0);
4321541Srgrimes}
4331541Srgrimes
4341541Srgrimes/*
4351541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
4361541Srgrimes * until it is killed by a signal.
4371541Srgrimes */
43812911Sphkstatic int
4391541Srgrimesnfssvc_nfsd(nsd, argp, p)
4401541Srgrimes	struct nfsd_srvargs *nsd;
4411541Srgrimes	caddr_t argp;
4421541Srgrimes	struct proc *p;
4431541Srgrimes{
4449336Sdfr	register struct mbuf *m;
4451541Srgrimes	register int siz;
4461541Srgrimes	register struct nfssvc_sock *slp;
4471541Srgrimes	register struct socket *so;
4481541Srgrimes	register int *solockp;
4499336Sdfr	struct nfsd *nfsd = nsd->nsd_nfsd;
4509336Sdfr	struct nfsrv_descript *nd = NULL;
4519336Sdfr	struct mbuf *mreq;
4529336Sdfr	int error = 0, cacherep, s, sotype, writes_todo;
4539336Sdfr	u_quad_t cur_usec;
4541541Srgrimes
4559336Sdfr#ifndef nolint
4569336Sdfr	cacherep = RC_DOIT;
4579336Sdfr	writes_todo = 0;
4589336Sdfr#endif
4591541Srgrimes	s = splnet();
4609336Sdfr	if (nfsd == (struct nfsd *)0) {
4619336Sdfr		nsd->nsd_nfsd = nfsd = (struct nfsd *)
4621541Srgrimes			malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
4639336Sdfr		bzero((caddr_t)nfsd, sizeof (struct nfsd));
4649336Sdfr		nfsd->nfsd_procp = p;
4659336Sdfr		TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
4661541Srgrimes		nfs_numnfsd++;
4671541Srgrimes	}
4681541Srgrimes	/*
4691541Srgrimes	 * Loop getting rpc requests until SIGKILL.
4701541Srgrimes	 */
4711541Srgrimes	for (;;) {
4729336Sdfr		if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
4739336Sdfr			while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
4743664Sphk			    (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
4759336Sdfr				nfsd->nfsd_flag |= NFSD_WAITING;
4761541Srgrimes				nfsd_waiting++;
4779336Sdfr				error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
4789336Sdfr				    "nfsd", 0);
4791541Srgrimes				nfsd_waiting--;
4801541Srgrimes				if (error)
4811541Srgrimes					goto done;
4821541Srgrimes			}
4839336Sdfr			if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
4843664Sphk			    (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
4853664Sphk				for (slp = nfssvc_sockhead.tqh_first; slp != 0;
4863664Sphk				    slp = slp->ns_chain.tqe_next) {
4871541Srgrimes				    if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
4881541Srgrimes					== (SLP_VALID | SLP_DOREC)) {
4891541Srgrimes					    slp->ns_flag &= ~SLP_DOREC;
4901541Srgrimes					    slp->ns_sref++;
4919336Sdfr					    nfsd->nfsd_slp = slp;
4921541Srgrimes					    break;
4931541Srgrimes				    }
4941541Srgrimes				}
4953664Sphk				if (slp == 0)
4963664Sphk					nfsd_head_flag &= ~NFSD_CHECKSLP;
4971541Srgrimes			}
4989336Sdfr			if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
4991541Srgrimes				continue;
5001541Srgrimes			if (slp->ns_flag & SLP_VALID) {
5011541Srgrimes				if (slp->ns_flag & SLP_DISCONN)
5021541Srgrimes					nfsrv_zapsock(slp);
5031541Srgrimes				else if (slp->ns_flag & SLP_NEEDQ) {
5041541Srgrimes					slp->ns_flag &= ~SLP_NEEDQ;
5051541Srgrimes					(void) nfs_sndlock(&slp->ns_solock,
5061541Srgrimes						(struct nfsreq *)0);
5071541Srgrimes					nfsrv_rcv(slp->ns_so, (caddr_t)slp,
5081541Srgrimes						M_WAIT);
5091541Srgrimes					nfs_sndunlock(&slp->ns_solock);
5101541Srgrimes				}
5119336Sdfr				error = nfsrv_dorec(slp, nfsd, &nd);
5129336Sdfr				cur_usec = (u_quad_t)time.tv_sec * 1000000 +
5139336Sdfr					(u_quad_t)time.tv_usec;
5149336Sdfr				if (error && slp->ns_tq.lh_first &&
5159336Sdfr				    slp->ns_tq.lh_first->nd_time <= cur_usec) {
5169336Sdfr					error = 0;
5179336Sdfr					cacherep = RC_DOIT;
5189336Sdfr					writes_todo = 1;
5199336Sdfr				} else
5209336Sdfr					writes_todo = 0;
5219336Sdfr				nfsd->nfsd_flag |= NFSD_REQINPROG;
5221541Srgrimes			}
5231541Srgrimes		} else {
5241541Srgrimes			error = 0;
5259336Sdfr			slp = nfsd->nfsd_slp;
5261541Srgrimes		}
5271541Srgrimes		if (error || (slp->ns_flag & SLP_VALID) == 0) {
5289336Sdfr			if (nd) {
5299336Sdfr				free((caddr_t)nd, M_NFSRVDESC);
5309336Sdfr				nd = NULL;
5319336Sdfr			}
5329336Sdfr			nfsd->nfsd_slp = (struct nfssvc_sock *)0;
5339336Sdfr			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
5341541Srgrimes			nfsrv_slpderef(slp);
5351541Srgrimes			continue;
5361541Srgrimes		}
5371541Srgrimes		splx(s);
5381541Srgrimes		so = slp->ns_so;
5391541Srgrimes		sotype = so->so_type;
5401541Srgrimes		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
5411541Srgrimes			solockp = &slp->ns_solock;
5421541Srgrimes		else
5431541Srgrimes			solockp = (int *)0;
5449336Sdfr		if (nd) {
5459336Sdfr		    nd->nd_starttime = time;
5469336Sdfr		    if (nd->nd_nam2)
5479336Sdfr			nd->nd_nam = nd->nd_nam2;
5489336Sdfr		    else
5499336Sdfr			nd->nd_nam = slp->ns_nam;
5501541Srgrimes
5519336Sdfr		    /*
5529336Sdfr		     * Check to see if authorization is needed.
5539336Sdfr		     */
5549336Sdfr		    if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
5559336Sdfr			nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
5569336Sdfr			nsd->nsd_haddr = mtod(nd->nd_nam,
5579336Sdfr			    struct sockaddr_in *)->sin_addr.s_addr;
5589336Sdfr			nsd->nsd_authlen = nfsd->nfsd_authlen;
5599336Sdfr			nsd->nsd_verflen = nfsd->nfsd_verflen;
5609336Sdfr			if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
5619336Sdfr				nfsd->nfsd_authlen) &&
5629336Sdfr			    !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
5639336Sdfr				nfsd->nfsd_verflen) &&
5649336Sdfr			    !copyout((caddr_t)nsd, argp, sizeof (*nsd)))
5659336Sdfr			    return (ENEEDAUTH);
5669336Sdfr			cacherep = RC_DROPIT;
5679336Sdfr		    } else
5689336Sdfr			cacherep = nfsrv_getcache(nd, slp, &mreq);
5691541Srgrimes
5709336Sdfr		    /*
5719336Sdfr		     * Check for just starting up for NQNFS and send
5729336Sdfr		     * fake "try again later" replies to the NQNFS clients.
5739336Sdfr		     */
5749336Sdfr		    if (notstarted && nqnfsstarttime <= time.tv_sec) {
5751541Srgrimes			if (modify_flag) {
5761541Srgrimes				nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
5771541Srgrimes				modify_flag = 0;
5781541Srgrimes			} else
5791541Srgrimes				notstarted = 0;
5809336Sdfr		    }
5819336Sdfr		    if (notstarted) {
5829336Sdfr			if ((nd->nd_flag & ND_NQNFS) == 0)
5831541Srgrimes				cacherep = RC_DROPIT;
5841541Srgrimes			else if (nd->nd_procnum != NFSPROC_WRITE) {
5851541Srgrimes				nd->nd_procnum = NFSPROC_NOOP;
5861541Srgrimes				nd->nd_repstat = NQNFS_TRYLATER;
5871541Srgrimes				cacherep = RC_DOIT;
5881541Srgrimes			} else
5891541Srgrimes				modify_flag = 1;
5909336Sdfr		    } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
5919336Sdfr			nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
5921541Srgrimes			nd->nd_procnum = NFSPROC_NOOP;
5939336Sdfr			nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
5941541Srgrimes			cacherep = RC_DOIT;
5959336Sdfr		    }
5961541Srgrimes		}
5971541Srgrimes
5989336Sdfr		/*
5999336Sdfr		 * Loop to get all the write rpc relies that have been
6009336Sdfr		 * gathered together.
6019336Sdfr		 */
6029336Sdfr		do {
6039336Sdfr		    switch (cacherep) {
6049336Sdfr		    case RC_DOIT:
6059336Sdfr			if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE &&
6069336Sdfr			    nfsrvw_procrastinate > 0 && !notstarted))
6079336Sdfr			    error = nfsrv_writegather(&nd, slp,
6089336Sdfr				nfsd->nfsd_procp, &mreq);
6099336Sdfr			else
6109336Sdfr			    error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
6119336Sdfr				slp, nfsd->nfsd_procp, &mreq);
6129336Sdfr			if (mreq == NULL)
6139336Sdfr				break;
6141541Srgrimes			if (error) {
6151541Srgrimes				if (nd->nd_procnum != NQNFSPROC_VACATED)
6161541Srgrimes					nfsstats.srv_errs++;
6179336Sdfr				nfsrv_updatecache(nd, FALSE, mreq);
6189336Sdfr				if (nd->nd_nam2)
6199336Sdfr					m_freem(nd->nd_nam2);
6201541Srgrimes				break;
6211541Srgrimes			}
6221541Srgrimes			nfsstats.srvrpccnt[nd->nd_procnum]++;
6239336Sdfr			nfsrv_updatecache(nd, TRUE, mreq);
6241541Srgrimes			nd->nd_mrep = (struct mbuf *)0;
6259336Sdfr		    case RC_REPLY:
6261541Srgrimes			m = mreq;
6271541Srgrimes			siz = 0;
6281541Srgrimes			while (m) {
6291541Srgrimes				siz += m->m_len;
6301541Srgrimes				m = m->m_next;
6311541Srgrimes			}
6321541Srgrimes			if (siz <= 0 || siz > NFS_MAXPACKET) {
6331541Srgrimes				printf("mbuf siz=%d\n",siz);
6341541Srgrimes				panic("Bad nfs svc reply");
6351541Srgrimes			}
6361541Srgrimes			m = mreq;
6371541Srgrimes			m->m_pkthdr.len = siz;
6381541Srgrimes			m->m_pkthdr.rcvif = (struct ifnet *)0;
6391541Srgrimes			/*
6401541Srgrimes			 * For stream protocols, prepend a Sun RPC
6411541Srgrimes			 * Record Mark.
6421541Srgrimes			 */
6431541Srgrimes			if (sotype == SOCK_STREAM) {
6441541Srgrimes				M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
6451541Srgrimes				*mtod(m, u_long *) = htonl(0x80000000 | siz);
6461541Srgrimes			}
6471541Srgrimes			if (solockp)
6481541Srgrimes				(void) nfs_sndlock(solockp, (struct nfsreq *)0);
6491541Srgrimes			if (slp->ns_flag & SLP_VALID)
6509336Sdfr			    error = nfs_send(so, nd->nd_nam2, m, NULL);
6511541Srgrimes			else {
6521541Srgrimes			    error = EPIPE;
6531541Srgrimes			    m_freem(m);
6541541Srgrimes			}
6551541Srgrimes			if (nfsrtton)
6569336Sdfr				nfsd_rt(sotype, nd, cacherep);
6579336Sdfr			if (nd->nd_nam2)
6589336Sdfr				MFREE(nd->nd_nam2, m);
6591541Srgrimes			if (nd->nd_mrep)
6601541Srgrimes				m_freem(nd->nd_mrep);
6611541Srgrimes			if (error == EPIPE)
6621541Srgrimes				nfsrv_zapsock(slp);
6631541Srgrimes			if (solockp)
6641541Srgrimes				nfs_sndunlock(solockp);
6651541Srgrimes			if (error == EINTR || error == ERESTART) {
6669336Sdfr				free((caddr_t)nd, M_NFSRVDESC);
6671541Srgrimes				nfsrv_slpderef(slp);
6681541Srgrimes				s = splnet();
6691541Srgrimes				goto done;
6701541Srgrimes			}
6711541Srgrimes			break;
6729336Sdfr		    case RC_DROPIT:
6731541Srgrimes			if (nfsrtton)
6749336Sdfr				nfsd_rt(sotype, nd, cacherep);
6751541Srgrimes			m_freem(nd->nd_mrep);
6769336Sdfr			m_freem(nd->nd_nam2);
6771541Srgrimes			break;
6789336Sdfr		    };
6799336Sdfr		    if (nd) {
6809336Sdfr			FREE((caddr_t)nd, M_NFSRVDESC);
6819336Sdfr			nd = NULL;
6829336Sdfr		    }
6839336Sdfr
6849336Sdfr		    /*
6859336Sdfr		     * Check to see if there are outstanding writes that
6869336Sdfr		     * need to be serviced.
6879336Sdfr		     */
6889336Sdfr		    cur_usec = (u_quad_t)time.tv_sec * 1000000 +
6899336Sdfr			(u_quad_t)time.tv_usec;
6909336Sdfr		    s = splsoftclock();
6919336Sdfr		    if (slp->ns_tq.lh_first &&
6929336Sdfr			slp->ns_tq.lh_first->nd_time <= cur_usec) {
6939336Sdfr			cacherep = RC_DOIT;
6949336Sdfr			writes_todo = 1;
6959336Sdfr		    } else
6969336Sdfr			writes_todo = 0;
6979336Sdfr		    splx(s);
6989336Sdfr		} while (writes_todo);
6991541Srgrimes		s = splnet();
7009336Sdfr		if (nfsrv_dorec(slp, nfsd, &nd)) {
7019336Sdfr			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
7029336Sdfr			nfsd->nfsd_slp = NULL;
7031541Srgrimes			nfsrv_slpderef(slp);
7041541Srgrimes		}
7051541Srgrimes	}
7061541Srgrimesdone:
7079336Sdfr	TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
7081541Srgrimes	splx(s);
7099336Sdfr	free((caddr_t)nfsd, M_NFSD);
7101541Srgrimes	nsd->nsd_nfsd = (struct nfsd *)0;
7111541Srgrimes	if (--nfs_numnfsd == 0)
7121541Srgrimes		nfsrv_init(TRUE);	/* Reinitialize everything */
7131541Srgrimes	return (error);
7141541Srgrimes}
71513416Sphk#endif /* NFS_NOSERVER */
7161541Srgrimes
71719449Sdfrint nfs_defect = 0;
71819449SdfrSYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, "");
71919449Sdfr
7201541Srgrimes/*
7211541Srgrimes * Asynchronous I/O daemons for client nfs.
7221541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache.
7231541Srgrimes * Never returns unless it fails or gets killed.
7241541Srgrimes */
72512911Sphkstatic int
7261541Srgrimesnfssvc_iod(p)
7271541Srgrimes	struct proc *p;
7281541Srgrimes{
7299336Sdfr	register struct buf *bp, *nbp;
7301541Srgrimes	register int i, myiod;
7319336Sdfr	struct vnode *vp;
73219449Sdfr	struct nfsmount *nmp;
7339336Sdfr	int error = 0, s;
7341541Srgrimes
7351541Srgrimes	/*
7361541Srgrimes	 * Assign my position or return error if too many already running
7371541Srgrimes	 */
7381541Srgrimes	myiod = -1;
7391541Srgrimes	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
7401541Srgrimes		if (nfs_asyncdaemon[i] == 0) {
7411541Srgrimes			nfs_asyncdaemon[i]++;
7421541Srgrimes			myiod = i;
7431541Srgrimes			break;
7441541Srgrimes		}
7451541Srgrimes	if (myiod == -1)
7461541Srgrimes		return (EBUSY);
7471541Srgrimes	nfs_numasync++;
7481541Srgrimes	/*
7491541Srgrimes	 * Just loop around doin our stuff until SIGKILL
7501541Srgrimes	 */
7511541Srgrimes	for (;;) {
75219449Sdfr	    while (((nmp = nfs_iodmount[myiod]) == NULL
75319449Sdfr		    || nmp->nm_bufq.tqh_first == NULL)
75419449Sdfr		   && error == 0) {
75519449Sdfr		if (nmp)
75619449Sdfr		    nmp->nm_bufqiods--;
7579336Sdfr		nfs_iodwant[myiod] = p;
75819449Sdfr		nfs_iodmount[myiod] = NULL;
7599336Sdfr		error = tsleep((caddr_t)&nfs_iodwant[myiod],
7609336Sdfr			PWAIT | PCATCH, "nfsidl", 0);
7619336Sdfr	    }
76219449Sdfr	    if (error) {
76319449Sdfr		nfs_asyncdaemon[myiod] = 0;
76419449Sdfr		if (nmp) nmp->nm_bufqiods--;
76519449Sdfr		nfs_iodmount[myiod] = NULL;
76619449Sdfr		nfs_numasync--;
76719449Sdfr		return (error);
76819449Sdfr	    }
76919449Sdfr	    while ((bp = nmp->nm_bufq.tqh_first) != NULL) {
7709336Sdfr		/* Take one off the front of the list */
77119449Sdfr		TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
77219449Sdfr		nmp->nm_bufqlen--;
77319449Sdfr		if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) {
77419449Sdfr		    nmp->nm_bufqwant = FALSE;
77519449Sdfr		    wakeup(&nmp->nm_bufq);
77619449Sdfr		}
7779336Sdfr		if (bp->b_flags & B_READ)
7789336Sdfr		    (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
77919449Sdfr		else
7809336Sdfr		    (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
78119449Sdfr
78219449Sdfr		/*
78319449Sdfr		 * If there are more than one iod on this mount, then defect
78419449Sdfr		 * so that the iods can be shared out fairly between the mounts
78519449Sdfr		 */
78619449Sdfr		if (nfs_defect && nmp->nm_bufqiods > 1) {
78719449Sdfr		    NFS_DPF(ASYNCIO,
78819449Sdfr			    ("nfssvc_iod: iod %d defecting from mount %p\n",
78919449Sdfr			     myiod, nmp));
79019449Sdfr		    nfs_iodmount[myiod] = NULL;
79119449Sdfr		    nmp->nm_bufqiods--;
79219449Sdfr		    break;
79319449Sdfr		}
7949336Sdfr	    }
7951541Srgrimes	}
7961541Srgrimes}
7971541Srgrimes
7981541Srgrimes/*
7991541Srgrimes * Shut down a socket associated with an nfssvc_sock structure.
8001541Srgrimes * Should be called with the send lock set, if required.
8011541Srgrimes * The trick here is to increment the sref at the start, so that the nfsds
8021541Srgrimes * will stop using it and clear ns_flag at the end so that it will not be
8031541Srgrimes * reassigned during cleanup.
8041541Srgrimes */
80512911Sphkstatic void
8061541Srgrimesnfsrv_zapsock(slp)
8071541Srgrimes	register struct nfssvc_sock *slp;
8081541Srgrimes{
8093664Sphk	register struct nfsuid *nuidp, *nnuidp;
8109336Sdfr	register struct nfsrv_descript *nwp, *nnwp;
8111541Srgrimes	struct socket *so;
8121541Srgrimes	struct file *fp;
8131541Srgrimes	struct mbuf *m;
8149336Sdfr	int s;
8151541Srgrimes
8161541Srgrimes	slp->ns_flag &= ~SLP_ALLFLAGS;
8173305Sphk	fp = slp->ns_fp;
8183305Sphk	if (fp) {
8191541Srgrimes		slp->ns_fp = (struct file *)0;
8201541Srgrimes		so = slp->ns_so;
8211541Srgrimes		so->so_upcall = NULL;
8221541Srgrimes		soshutdown(so, 2);
8231541Srgrimes		closef(fp, (struct proc *)0);
8241541Srgrimes		if (slp->ns_nam)
8251541Srgrimes			MFREE(slp->ns_nam, m);
8261541Srgrimes		m_freem(slp->ns_raw);
8271541Srgrimes		m_freem(slp->ns_rec);
8283664Sphk		for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0;
8293664Sphk		    nuidp = nnuidp) {
8303664Sphk			nnuidp = nuidp->nu_lru.tqe_next;
8313664Sphk			LIST_REMOVE(nuidp, nu_hash);
8323664Sphk			TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
8339336Sdfr			if (nuidp->nu_flag & NU_NAM)
8349336Sdfr				m_freem(nuidp->nu_nam);
8353664Sphk			free((caddr_t)nuidp, M_NFSUID);
8361541Srgrimes		}
8379336Sdfr		s = splsoftclock();
8389336Sdfr		for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
8399336Sdfr			nnwp = nwp->nd_tq.le_next;
8409336Sdfr			LIST_REMOVE(nwp, nd_tq);
8419336Sdfr			free((caddr_t)nwp, M_NFSRVDESC);
8429336Sdfr		}
8439336Sdfr		LIST_INIT(&slp->ns_tq);
8449336Sdfr		splx(s);
8451541Srgrimes	}
8461541Srgrimes}
8471541Srgrimes
8481541Srgrimes/*
8491541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting
8501541Srgrimes * on this mount point porpous out of the kernel and do it.
8511541Srgrimes */
8521549Srgrimesint
8539336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
8541541Srgrimes	register struct nfsmount *nmp;
8551541Srgrimes	struct nfsreq *rep;
8561541Srgrimes	struct ucred *cred;
8571541Srgrimes	char **auth_str;
8581541Srgrimes	int *auth_len;
8599336Sdfr	char *verf_str;
8609336Sdfr	int *verf_len;
8619336Sdfr	NFSKERBKEY_T key;		/* return session key */
8621541Srgrimes{
8631541Srgrimes	int error = 0;
8641541Srgrimes
8651541Srgrimes	while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
8661541Srgrimes		nmp->nm_flag |= NFSMNT_WANTAUTH;
8671541Srgrimes		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
8681541Srgrimes			"nfsauth1", 2 * hz);
8693305Sphk		error = nfs_sigintr(nmp, rep, rep->r_procp);
8703305Sphk		if (error) {
8711541Srgrimes			nmp->nm_flag &= ~NFSMNT_WANTAUTH;
8721541Srgrimes			return (error);
8731541Srgrimes		}
8741541Srgrimes	}
8751541Srgrimes	nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
8761541Srgrimes	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
8779336Sdfr	nmp->nm_authlen = RPCAUTH_MAXSIZ;
8789336Sdfr	nmp->nm_verfstr = verf_str;
8799336Sdfr	nmp->nm_verflen = *verf_len;
8801541Srgrimes	nmp->nm_authuid = cred->cr_uid;
8811541Srgrimes	wakeup((caddr_t)&nmp->nm_authstr);
8821541Srgrimes
8831541Srgrimes	/*
8841541Srgrimes	 * And wait for mount_nfs to do its stuff.
8851541Srgrimes	 */
8861541Srgrimes	while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
8871541Srgrimes		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
8881541Srgrimes			"nfsauth2", 2 * hz);
8891541Srgrimes		error = nfs_sigintr(nmp, rep, rep->r_procp);
8901541Srgrimes	}
8911541Srgrimes	if (nmp->nm_flag & NFSMNT_AUTHERR) {
8921541Srgrimes		nmp->nm_flag &= ~NFSMNT_AUTHERR;
8931541Srgrimes		error = EAUTH;
8941541Srgrimes	}
8951541Srgrimes	if (error)
8961541Srgrimes		free((caddr_t)*auth_str, M_TEMP);
8971541Srgrimes	else {
8981541Srgrimes		*auth_len = nmp->nm_authlen;
8999336Sdfr		*verf_len = nmp->nm_verflen;
9009336Sdfr		bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
9011541Srgrimes	}
9021541Srgrimes	nmp->nm_flag &= ~NFSMNT_HASAUTH;
9031541Srgrimes	nmp->nm_flag |= NFSMNT_WAITAUTH;
9041541Srgrimes	if (nmp->nm_flag & NFSMNT_WANTAUTH) {
9051541Srgrimes		nmp->nm_flag &= ~NFSMNT_WANTAUTH;
9061541Srgrimes		wakeup((caddr_t)&nmp->nm_authtype);
9071541Srgrimes	}
9081541Srgrimes	return (error);
9091541Srgrimes}
9101541Srgrimes
9111541Srgrimes/*
9129336Sdfr * Get a nickname authenticator and verifier.
9139336Sdfr */
9149336Sdfrint
9159336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
9169336Sdfr	struct nfsmount *nmp;
9179336Sdfr	struct ucred *cred;
9189336Sdfr	char **auth_str;
9199336Sdfr	int *auth_len;
9209336Sdfr	char *verf_str;
9219336Sdfr	int verf_len;
9229336Sdfr{
9239336Sdfr	register struct nfsuid *nuidp;
9249336Sdfr	register u_long *nickp, *verfp;
9259336Sdfr	struct timeval ktvin, ktvout;
9269336Sdfr
9279336Sdfr#ifdef DIAGNOSTIC
9289336Sdfr	if (verf_len < (4 * NFSX_UNSIGNED))
9299336Sdfr		panic("nfs_getnickauth verf too small");
9309336Sdfr#endif
9319336Sdfr	for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
9329336Sdfr	    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
9339336Sdfr		if (nuidp->nu_cr.cr_uid == cred->cr_uid)
9349336Sdfr			break;
9359336Sdfr	}
9369336Sdfr	if (!nuidp || nuidp->nu_expire < time.tv_sec)
9379336Sdfr		return (EACCES);
9389336Sdfr
9399336Sdfr	/*
9409336Sdfr	 * Move to the end of the lru list (end of lru == most recently used).
9419336Sdfr	 */
9429336Sdfr	TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
9439336Sdfr	TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
9449336Sdfr
9459336Sdfr	nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
9469336Sdfr	*nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
9479336Sdfr	*nickp = txdr_unsigned(nuidp->nu_nickname);
9489336Sdfr	*auth_str = (char *)nickp;
9499336Sdfr	*auth_len = 2 * NFSX_UNSIGNED;
9509336Sdfr
9519336Sdfr	/*
9529336Sdfr	 * Now we must encrypt the verifier and package it up.
9539336Sdfr	 */
9549336Sdfr	verfp = (u_long *)verf_str;
9559336Sdfr	*verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
9569336Sdfr	if (time.tv_sec > nuidp->nu_timestamp.tv_sec ||
9579336Sdfr	    (time.tv_sec == nuidp->nu_timestamp.tv_sec &&
9589336Sdfr	     time.tv_usec > nuidp->nu_timestamp.tv_usec))
9599336Sdfr		nuidp->nu_timestamp = time;
9609336Sdfr	else
9619336Sdfr		nuidp->nu_timestamp.tv_usec++;
9629336Sdfr	ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
9639336Sdfr	ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
9649336Sdfr
9659336Sdfr	/*
9669336Sdfr	 * Now encrypt the timestamp verifier in ecb mode using the session
9679336Sdfr	 * key.
9689336Sdfr	 */
9699336Sdfr#ifdef NFSKERB
9709336Sdfr	XXX
9719336Sdfr#endif
9729336Sdfr
9739336Sdfr	*verfp++ = ktvout.tv_sec;
9749336Sdfr	*verfp++ = ktvout.tv_usec;
9759336Sdfr	*verfp = 0;
9769336Sdfr	return (0);
9779336Sdfr}
9789336Sdfr
9799336Sdfr/*
9809336Sdfr * Save the current nickname in a hash list entry on the mount point.
9819336Sdfr */
9829336Sdfrint
9839336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
9849336Sdfr	register struct nfsmount *nmp;
9859336Sdfr	struct ucred *cred;
9869336Sdfr	int len;
9879336Sdfr	NFSKERBKEY_T key;
9889336Sdfr	struct mbuf **mdp;
9899336Sdfr	char **dposp;
9909336Sdfr	struct mbuf *mrep;
9919336Sdfr{
9929336Sdfr	register struct nfsuid *nuidp;
9939336Sdfr	register u_long *tl;
9949336Sdfr	register long t1;
9959336Sdfr	struct mbuf *md = *mdp;
9969336Sdfr	struct timeval ktvin, ktvout;
9979336Sdfr	u_long nick;
9989336Sdfr	char *dpos = *dposp, *cp2;
9999336Sdfr	int deltasec, error = 0;
10009336Sdfr
10019336Sdfr	if (len == (3 * NFSX_UNSIGNED)) {
10029336Sdfr		nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
10039336Sdfr		ktvin.tv_sec = *tl++;
10049336Sdfr		ktvin.tv_usec = *tl++;
10059336Sdfr		nick = fxdr_unsigned(u_long, *tl);
10069336Sdfr
10079336Sdfr		/*
10089336Sdfr		 * Decrypt the timestamp in ecb mode.
10099336Sdfr		 */
10109336Sdfr#ifdef NFSKERB
10119336Sdfr		XXX
10129336Sdfr#endif
10139336Sdfr		ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
10149336Sdfr		ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
10159336Sdfr		deltasec = time.tv_sec - ktvout.tv_sec;
10169336Sdfr		if (deltasec < 0)
10179336Sdfr			deltasec = -deltasec;
10189336Sdfr		/*
10199336Sdfr		 * If ok, add it to the hash list for the mount point.
10209336Sdfr		 */
10219336Sdfr		if (deltasec <= NFS_KERBCLOCKSKEW) {
10229336Sdfr			if (nmp->nm_numuids < nuidhash_max) {
10239336Sdfr				nmp->nm_numuids++;
10249336Sdfr				nuidp = (struct nfsuid *)
10259336Sdfr				   malloc(sizeof (struct nfsuid), M_NFSUID,
10269336Sdfr					M_WAITOK);
10279336Sdfr			} else {
10289336Sdfr				nuidp = nmp->nm_uidlruhead.tqh_first;
10299336Sdfr				LIST_REMOVE(nuidp, nu_hash);
10309336Sdfr				TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
10319336Sdfr					nu_lru);
10329336Sdfr			}
10339336Sdfr			nuidp->nu_flag = 0;
10349336Sdfr			nuidp->nu_cr.cr_uid = cred->cr_uid;
10359336Sdfr			nuidp->nu_expire = time.tv_sec + NFS_KERBTTL;
10369336Sdfr			nuidp->nu_timestamp = ktvout;
10379336Sdfr			nuidp->nu_nickname = nick;
10389336Sdfr			bcopy(key, nuidp->nu_key, sizeof (key));
10399336Sdfr			TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
10409336Sdfr				nu_lru);
10419336Sdfr			LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
10429336Sdfr				nuidp, nu_hash);
10439336Sdfr		}
10449336Sdfr	} else
10459336Sdfr		nfsm_adv(nfsm_rndup(len));
10469336Sdfrnfsmout:
10479336Sdfr	*mdp = md;
10489336Sdfr	*dposp = dpos;
10499336Sdfr	return (error);
10509336Sdfr}
10519336Sdfr
105213416Sphk#ifndef NFS_NOSERVER
105322521Sdyson
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