nfs_nfsiod.c revision 12274
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
3712274Sbde * $Id: nfs_syscalls.c,v 1.8 1995/10/29 15:33:11 phk Exp $
381541Srgrimes */
391541Srgrimes
401541Srgrimes#include <sys/param.h>
411541Srgrimes#include <sys/systm.h>
4212274Sbde#include <sys/sysproto.h>
431541Srgrimes#include <sys/kernel.h>
441541Srgrimes#include <sys/file.h>
451541Srgrimes#include <sys/stat.h>
461541Srgrimes#include <sys/vnode.h>
471541Srgrimes#include <sys/mount.h>
481541Srgrimes#include <sys/proc.h>
491541Srgrimes#include <sys/uio.h>
501541Srgrimes#include <sys/malloc.h>
511541Srgrimes#include <sys/buf.h>
521541Srgrimes#include <sys/mbuf.h>
531541Srgrimes#include <sys/socket.h>
541541Srgrimes#include <sys/socketvar.h>
551541Srgrimes#include <sys/domain.h>
561541Srgrimes#include <sys/protosw.h>
571541Srgrimes#include <sys/namei.h>
581541Srgrimes#include <sys/syslog.h>
591541Srgrimes
601541Srgrimes#include <netinet/in.h>
611541Srgrimes#include <netinet/tcp.h>
621541Srgrimes#ifdef ISO
631541Srgrimes#include <netiso/iso.h>
641541Srgrimes#endif
659336Sdfr#include <nfs/xdr_subs.h>
661541Srgrimes#include <nfs/rpcv2.h>
679336Sdfr#include <nfs/nfsproto.h>
681541Srgrimes#include <nfs/nfs.h>
699336Sdfr#include <nfs/nfsm_subs.h>
701541Srgrimes#include <nfs/nfsrvcache.h>
711541Srgrimes#include <nfs/nfsmount.h>
721541Srgrimes#include <nfs/nfsnode.h>
731541Srgrimes#include <nfs/nqnfs.h>
741541Srgrimes#include <nfs/nfsrtt.h>
751541Srgrimes
761549Srgrimesvoid	nfsrv_zapsock	__P((struct nfssvc_sock *));
771549Srgrimes
781541Srgrimes/* Global defs. */
799336Sdfrextern int (*nfsrv3_procs[NFS_NPROCS])();
801541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
811541Srgrimesextern int nfs_numasync;
821541Srgrimesextern time_t nqnfsstarttime;
831541Srgrimesextern int nqsrv_writeslack;
841541Srgrimesextern int nfsrtton;
859336Sdfrextern struct nfsstats nfsstats;
869336Sdfrextern int nfsrvw_procrastinate;
871541Srgrimesstruct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
881541Srgrimesint nuidhash_max = NFS_MAXUIDHASH;
891541Srgrimesstatic int nfs_numnfsd = 0;
901541Srgrimesint nfsd_waiting = 0;
911541Srgrimesstatic int notstarted = 1;
921541Srgrimesstatic int modify_flag = 0;
931541Srgrimesstatic struct nfsdrt nfsdrt;
941541Srgrimesvoid nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock();
951541Srgrimesstatic void nfsd_rt();
963664Sphkvoid nfsrv_slpderef();
971541Srgrimes
981541Srgrimes#define	TRUE	1
991541Srgrimes#define	FALSE	0
1001541Srgrimes
1011541Srgrimesstatic int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
1021541Srgrimes/*
1031541Srgrimes * NFS server system calls
1041541Srgrimes * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
1051541Srgrimes */
1061541Srgrimes
1071541Srgrimes/*
1081541Srgrimes * Get file handle system call
1091541Srgrimes */
11012274Sbde#ifndef _SYS_SYSPROTO_H_
1111541Srgrimesstruct getfh_args {
1121541Srgrimes	char	*fname;
1131541Srgrimes	fhandle_t *fhp;
1141541Srgrimes};
11512274Sbde#endif
1161549Srgrimesint
1171541Srgrimesgetfh(p, uap, retval)
1181541Srgrimes	struct proc *p;
1191541Srgrimes	register struct getfh_args *uap;
1201541Srgrimes	int *retval;
1211541Srgrimes{
1221541Srgrimes	register struct vnode *vp;
1231541Srgrimes	fhandle_t fh;
1241541Srgrimes	int error;
1251541Srgrimes	struct nameidata nd;
1261541Srgrimes
1271541Srgrimes	/*
1281541Srgrimes	 * Must be super user
1291541Srgrimes	 */
1303305Sphk	error = suser(p->p_ucred, &p->p_acflag);
1313305Sphk	if(error)
1321541Srgrimes		return (error);
1331541Srgrimes	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1343305Sphk	error = namei(&nd);
1353305Sphk	if (error)
1361541Srgrimes		return (error);
1371541Srgrimes	vp = nd.ni_vp;
1381541Srgrimes	bzero((caddr_t)&fh, sizeof(fh));
1391541Srgrimes	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1401541Srgrimes	error = VFS_VPTOFH(vp, &fh.fh_fid);
1411541Srgrimes	vput(vp);
1421541Srgrimes	if (error)
1431541Srgrimes		return (error);
1441541Srgrimes	error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
1451541Srgrimes	return (error);
1461541Srgrimes}
1471541Srgrimes
1481541Srgrimes/*
1491541Srgrimes * Nfs server psuedo system call for the nfsd's
1501541Srgrimes * Based on the flag value it either:
1511541Srgrimes * - adds a socket to the selection list
1521541Srgrimes * - remains in the kernel as an nfsd
1531541Srgrimes * - remains in the kernel as an nfsiod
1541541Srgrimes */
15512274Sbde#ifndef _SYS_SYSPROTO_H_
1561541Srgrimesstruct nfssvc_args {
1571541Srgrimes	int flag;
1581541Srgrimes	caddr_t argp;
1591541Srgrimes};
16012274Sbde#endif
1611549Srgrimesint
1621541Srgrimesnfssvc(p, uap, retval)
1631541Srgrimes	struct proc *p;
1641541Srgrimes	register struct nfssvc_args *uap;
1651541Srgrimes	int *retval;
1661541Srgrimes{
1671541Srgrimes	struct nameidata nd;
1681541Srgrimes	struct file *fp;
1691541Srgrimes	struct mbuf *nam;
1701541Srgrimes	struct nfsd_args nfsdarg;
1711541Srgrimes	struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
1721541Srgrimes	struct nfsd_cargs ncd;
1731541Srgrimes	struct nfsd *nfsd;
1741541Srgrimes	struct nfssvc_sock *slp;
1753664Sphk	struct nfsuid *nuidp;
1761541Srgrimes	struct nfsmount *nmp;
1771541Srgrimes	int error;
1781541Srgrimes
1791541Srgrimes	/*
1801541Srgrimes	 * Must be super user
1811541Srgrimes	 */
1823305Sphk	error = suser(p->p_ucred, &p->p_acflag);
1833305Sphk	if(error)
1841541Srgrimes		return (error);
1853664Sphk	while (nfssvc_sockhead_flag & SLP_INIT) {
1863664Sphk		 nfssvc_sockhead_flag |= SLP_WANTINIT;
1871541Srgrimes		(void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
1881541Srgrimes	}
1891541Srgrimes	if (uap->flag & NFSSVC_BIOD)
1901541Srgrimes		error = nfssvc_iod(p);
1911541Srgrimes	else if (uap->flag & NFSSVC_MNTD) {
1923305Sphk		error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd));
1933305Sphk		if (error)
1941541Srgrimes			return (error);
1951541Srgrimes		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1961541Srgrimes			ncd.ncd_dirp, p);
1973305Sphk		error = namei(&nd);
1983305Sphk		if (error)
1991541Srgrimes			return (error);
2001541Srgrimes		if ((nd.ni_vp->v_flag & VROOT) == 0)
2011541Srgrimes			error = EINVAL;
2021541Srgrimes		nmp = VFSTONFS(nd.ni_vp->v_mount);
2031541Srgrimes		vput(nd.ni_vp);
2041541Srgrimes		if (error)
2051541Srgrimes			return (error);
2061541Srgrimes		if ((nmp->nm_flag & NFSMNT_MNTD) &&
2071541Srgrimes			(uap->flag & NFSSVC_GOTAUTH) == 0)
2081541Srgrimes			return (0);
2091541Srgrimes		nmp->nm_flag |= NFSMNT_MNTD;
2101541Srgrimes		error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag,
2111541Srgrimes			uap->argp, p);
2121541Srgrimes	} else if (uap->flag & NFSSVC_ADDSOCK) {
2133305Sphk		error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
2143305Sphk		if (error)
2151541Srgrimes			return (error);
2163305Sphk		error = getsock(p->p_fd, nfsdarg.sock, &fp);
2173305Sphk		if (error)
2181541Srgrimes			return (error);
2191541Srgrimes		/*
2201541Srgrimes		 * Get the client address for connected sockets.
2211541Srgrimes		 */
2221541Srgrimes		if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
2231541Srgrimes			nam = (struct mbuf *)0;
2243305Sphk		else {
2253305Sphk			error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
2263305Sphk				MT_SONAME);
2273305Sphk			if (error)
2283305Sphk				return (error);
2293305Sphk		}
2301541Srgrimes		error = nfssvc_addsock(fp, nam);
2311541Srgrimes	} else {
2323305Sphk		error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd));
2333305Sphk		if (error)
2341541Srgrimes			return (error);
2353305Sphk		if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) &&
2369336Sdfr			(nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
2379336Sdfr			slp = nfsd->nfsd_slp;
2381541Srgrimes
2391541Srgrimes			/*
2401541Srgrimes			 * First check to see if another nfsd has already
2411541Srgrimes			 * added this credential.
2421541Srgrimes			 */
2439336Sdfr			for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
2443664Sphk			    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
2459336Sdfr				if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
2469336Sdfr				    (!nfsd->nfsd_nd->nd_nam2 ||
2479336Sdfr				     netaddr_match(NU_NETFAM(nuidp),
2489336Sdfr				     &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
2491541Srgrimes					break;
2501541Srgrimes			}
2519336Sdfr			if (nuidp) {
2529336Sdfr			    nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
2539336Sdfr			    nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
2549336Sdfr			} else {
2551541Srgrimes			    /*
2561541Srgrimes			     * Nope, so we will.
2571541Srgrimes			     */
2581541Srgrimes			    if (slp->ns_numuids < nuidhash_max) {
2591541Srgrimes				slp->ns_numuids++;
2601541Srgrimes				nuidp = (struct nfsuid *)
2611541Srgrimes				   malloc(sizeof (struct nfsuid), M_NFSUID,
2621541Srgrimes					M_WAITOK);
2631541Srgrimes			    } else
2641541Srgrimes				nuidp = (struct nfsuid *)0;
2651541Srgrimes			    if ((slp->ns_flag & SLP_VALID) == 0) {
2661541Srgrimes				if (nuidp)
2671541Srgrimes				    free((caddr_t)nuidp, M_NFSUID);
2681541Srgrimes			    } else {
2691541Srgrimes				if (nuidp == (struct nfsuid *)0) {
2703664Sphk				    nuidp = slp->ns_uidlruhead.tqh_first;
2713664Sphk				    LIST_REMOVE(nuidp, nu_hash);
2723664Sphk				    TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
2733664Sphk					nu_lru);
2749336Sdfr				    if (nuidp->nu_flag & NU_NAM)
2759336Sdfr					m_freem(nuidp->nu_nam);
2761541Srgrimes			        }
2779336Sdfr				nuidp->nu_flag = 0;
2781541Srgrimes				nuidp->nu_cr = nsd->nsd_cr;
2791541Srgrimes				if (nuidp->nu_cr.cr_ngroups > NGROUPS)
2809336Sdfr				    nuidp->nu_cr.cr_ngroups = NGROUPS;
2811541Srgrimes				nuidp->nu_cr.cr_ref = 1;
2829336Sdfr				nuidp->nu_timestamp = nsd->nsd_timestamp;
2839336Sdfr				nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl;
2849336Sdfr				/*
2859336Sdfr				 * and save the session key in nu_key.
2869336Sdfr				 */
2879336Sdfr				bcopy(nsd->nsd_key, nuidp->nu_key,
2889336Sdfr				    sizeof (nsd->nsd_key));
2899336Sdfr				if (nfsd->nfsd_nd->nd_nam2) {
2909336Sdfr				    struct sockaddr_in *saddr;
2919336Sdfr
2929336Sdfr				    saddr = mtod(nfsd->nfsd_nd->nd_nam2,
2939336Sdfr					 struct sockaddr_in *);
2949336Sdfr				    switch (saddr->sin_family) {
2959336Sdfr				    case AF_INET:
2969336Sdfr					nuidp->nu_flag |= NU_INETADDR;
2979336Sdfr					nuidp->nu_inetaddr =
2989336Sdfr					     saddr->sin_addr.s_addr;
2999336Sdfr					break;
3009336Sdfr				    case AF_ISO:
3019336Sdfr				    default:
3029336Sdfr					nuidp->nu_flag |= NU_NAM;
3039336Sdfr					nuidp->nu_nam = m_copym(
3049336Sdfr					    nfsd->nfsd_nd->nd_nam2, 0,
3059336Sdfr					     M_COPYALL, M_WAIT);
3069336Sdfr					break;
3079336Sdfr				    };
3089336Sdfr				}
3093664Sphk				TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
3103664Sphk					nu_lru);
3113664Sphk				LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
3123664Sphk					nuidp, nu_hash);
3139336Sdfr				nfsrv_setcred(&nuidp->nu_cr,
3149336Sdfr				    &nfsd->nfsd_nd->nd_cr);
3159336Sdfr				nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
3161541Srgrimes			    }
3171541Srgrimes			}
3181541Srgrimes		}
3191541Srgrimes		if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
3209336Sdfr			nfsd->nfsd_flag |= NFSD_AUTHFAIL;
3211541Srgrimes		error = nfssvc_nfsd(nsd, uap->argp, p);
3221541Srgrimes	}
3231541Srgrimes	if (error == EINTR || error == ERESTART)
3241541Srgrimes		error = 0;
3251541Srgrimes	return (error);
3261541Srgrimes}
3271541Srgrimes
3281541Srgrimes/*
3291541Srgrimes * Adds a socket to the list for servicing by nfsds.
3301541Srgrimes */
3311549Srgrimesint
3321541Srgrimesnfssvc_addsock(fp, mynam)
3331541Srgrimes	struct file *fp;
3341541Srgrimes	struct mbuf *mynam;
3351541Srgrimes{
3361541Srgrimes	register struct mbuf *m;
3371541Srgrimes	register int siz;
3381541Srgrimes	register struct nfssvc_sock *slp;
3391541Srgrimes	register struct socket *so;
3401541Srgrimes	struct nfssvc_sock *tslp;
3411541Srgrimes	int error, s;
3421541Srgrimes
3431541Srgrimes	so = (struct socket *)fp->f_data;
3441541Srgrimes	tslp = (struct nfssvc_sock *)0;
3451541Srgrimes	/*
3461541Srgrimes	 * Add it to the list, as required.
3471541Srgrimes	 */
3481541Srgrimes	if (so->so_proto->pr_protocol == IPPROTO_UDP) {
3491541Srgrimes		tslp = nfs_udpsock;
3501541Srgrimes		if (tslp->ns_flag & SLP_VALID) {
3511541Srgrimes			m_freem(mynam);
3521541Srgrimes			return (EPERM);
3531541Srgrimes		}
3541541Srgrimes#ifdef ISO
3551541Srgrimes	} else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
3561541Srgrimes		tslp = nfs_cltpsock;
3571541Srgrimes		if (tslp->ns_flag & SLP_VALID) {
3581541Srgrimes			m_freem(mynam);
3591541Srgrimes			return (EPERM);
3601541Srgrimes		}
3611541Srgrimes#endif /* ISO */
3621541Srgrimes	}
3631541Srgrimes	if (so->so_type == SOCK_STREAM)
3641541Srgrimes		siz = NFS_MAXPACKET + sizeof (u_long);
3651541Srgrimes	else
3661541Srgrimes		siz = NFS_MAXPACKET;
3678876Srgrimes	error = soreserve(so, siz, siz);
3683305Sphk	if (error) {
3691541Srgrimes		m_freem(mynam);
3701541Srgrimes		return (error);
3711541Srgrimes	}
3721541Srgrimes
3731541Srgrimes	/*
3741541Srgrimes	 * Set protocol specific options { for now TCP only } and
3751541Srgrimes	 * reserve some space. For datagram sockets, this can get called
3761541Srgrimes	 * repeatedly for the same socket, but that isn't harmful.
3771541Srgrimes	 */
3781541Srgrimes	if (so->so_type == SOCK_STREAM) {
3791541Srgrimes		MGET(m, M_WAIT, MT_SOOPTS);
3801541Srgrimes		*mtod(m, int *) = 1;
3811541Srgrimes		m->m_len = sizeof(int);
3821541Srgrimes		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
3831541Srgrimes	}
3841541Srgrimes	if (so->so_proto->pr_domain->dom_family == AF_INET &&
3851541Srgrimes	    so->so_proto->pr_protocol == IPPROTO_TCP) {
3861541Srgrimes		MGET(m, M_WAIT, MT_SOOPTS);
3871541Srgrimes		*mtod(m, int *) = 1;
3881541Srgrimes		m->m_len = sizeof(int);
3891541Srgrimes		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
3901541Srgrimes	}
3911541Srgrimes	so->so_rcv.sb_flags &= ~SB_NOINTR;
3921541Srgrimes	so->so_rcv.sb_timeo = 0;
3931541Srgrimes	so->so_snd.sb_flags &= ~SB_NOINTR;
3941541Srgrimes	so->so_snd.sb_timeo = 0;
3951541Srgrimes	if (tslp)
3961541Srgrimes		slp = tslp;
3971541Srgrimes	else {
3981541Srgrimes		slp = (struct nfssvc_sock *)
3991541Srgrimes			malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
4001541Srgrimes		bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
4013664Sphk		TAILQ_INIT(&slp->ns_uidlruhead);
4023664Sphk		TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
4031541Srgrimes	}
4041541Srgrimes	slp->ns_so = so;
4051541Srgrimes	slp->ns_nam = mynam;
4061541Srgrimes	fp->f_count++;
4071541Srgrimes	slp->ns_fp = fp;
4081541Srgrimes	s = splnet();
4091541Srgrimes	so->so_upcallarg = (caddr_t)slp;
4101541Srgrimes	so->so_upcall = nfsrv_rcv;
4111541Srgrimes	slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
4121541Srgrimes	nfsrv_wakenfsd(slp);
4131541Srgrimes	splx(s);
4141541Srgrimes	return (0);
4151541Srgrimes}
4161541Srgrimes
4171541Srgrimes/*
4181541Srgrimes * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
4191541Srgrimes * until it is killed by a signal.
4201541Srgrimes */
4211549Srgrimesint
4221541Srgrimesnfssvc_nfsd(nsd, argp, p)
4231541Srgrimes	struct nfsd_srvargs *nsd;
4241541Srgrimes	caddr_t argp;
4251541Srgrimes	struct proc *p;
4261541Srgrimes{
4279336Sdfr	register struct mbuf *m;
4281541Srgrimes	register int siz;
4291541Srgrimes	register struct nfssvc_sock *slp;
4301541Srgrimes	register struct socket *so;
4311541Srgrimes	register int *solockp;
4329336Sdfr	struct nfsd *nfsd = nsd->nsd_nfsd;
4339336Sdfr	struct nfsrv_descript *nd = NULL;
4349336Sdfr	struct mbuf *mreq;
4359336Sdfr	int error = 0, cacherep, s, sotype, writes_todo;
4369336Sdfr	u_quad_t cur_usec;
4371541Srgrimes
4389336Sdfr#ifndef nolint
4399336Sdfr	cacherep = RC_DOIT;
4409336Sdfr	writes_todo = 0;
4419336Sdfr#endif
4421541Srgrimes	s = splnet();
4439336Sdfr	if (nfsd == (struct nfsd *)0) {
4449336Sdfr		nsd->nsd_nfsd = nfsd = (struct nfsd *)
4451541Srgrimes			malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
4469336Sdfr		bzero((caddr_t)nfsd, sizeof (struct nfsd));
4479336Sdfr		nfsd->nfsd_procp = p;
4489336Sdfr		TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
4491541Srgrimes		nfs_numnfsd++;
4501541Srgrimes	}
4511541Srgrimes	/*
4521541Srgrimes	 * Loop getting rpc requests until SIGKILL.
4531541Srgrimes	 */
4541541Srgrimes	for (;;) {
4559336Sdfr		if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
4569336Sdfr			while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
4573664Sphk			    (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
4589336Sdfr				nfsd->nfsd_flag |= NFSD_WAITING;
4591541Srgrimes				nfsd_waiting++;
4609336Sdfr				error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
4619336Sdfr				    "nfsd", 0);
4621541Srgrimes				nfsd_waiting--;
4631541Srgrimes				if (error)
4641541Srgrimes					goto done;
4651541Srgrimes			}
4669336Sdfr			if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
4673664Sphk			    (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
4683664Sphk				for (slp = nfssvc_sockhead.tqh_first; slp != 0;
4693664Sphk				    slp = slp->ns_chain.tqe_next) {
4701541Srgrimes				    if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
4711541Srgrimes					== (SLP_VALID | SLP_DOREC)) {
4721541Srgrimes					    slp->ns_flag &= ~SLP_DOREC;
4731541Srgrimes					    slp->ns_sref++;
4749336Sdfr					    nfsd->nfsd_slp = slp;
4751541Srgrimes					    break;
4761541Srgrimes				    }
4771541Srgrimes				}
4783664Sphk				if (slp == 0)
4793664Sphk					nfsd_head_flag &= ~NFSD_CHECKSLP;
4801541Srgrimes			}
4819336Sdfr			if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
4821541Srgrimes				continue;
4831541Srgrimes			if (slp->ns_flag & SLP_VALID) {
4841541Srgrimes				if (slp->ns_flag & SLP_DISCONN)
4851541Srgrimes					nfsrv_zapsock(slp);
4861541Srgrimes				else if (slp->ns_flag & SLP_NEEDQ) {
4871541Srgrimes					slp->ns_flag &= ~SLP_NEEDQ;
4881541Srgrimes					(void) nfs_sndlock(&slp->ns_solock,
4891541Srgrimes						(struct nfsreq *)0);
4901541Srgrimes					nfsrv_rcv(slp->ns_so, (caddr_t)slp,
4911541Srgrimes						M_WAIT);
4921541Srgrimes					nfs_sndunlock(&slp->ns_solock);
4931541Srgrimes				}
4949336Sdfr				error = nfsrv_dorec(slp, nfsd, &nd);
4959336Sdfr				cur_usec = (u_quad_t)time.tv_sec * 1000000 +
4969336Sdfr					(u_quad_t)time.tv_usec;
4979336Sdfr				if (error && slp->ns_tq.lh_first &&
4989336Sdfr				    slp->ns_tq.lh_first->nd_time <= cur_usec) {
4999336Sdfr					error = 0;
5009336Sdfr					cacherep = RC_DOIT;
5019336Sdfr					writes_todo = 1;
5029336Sdfr				} else
5039336Sdfr					writes_todo = 0;
5049336Sdfr				nfsd->nfsd_flag |= NFSD_REQINPROG;
5051541Srgrimes			}
5061541Srgrimes		} else {
5071541Srgrimes			error = 0;
5089336Sdfr			slp = nfsd->nfsd_slp;
5091541Srgrimes		}
5101541Srgrimes		if (error || (slp->ns_flag & SLP_VALID) == 0) {
5119336Sdfr			if (nd) {
5129336Sdfr				free((caddr_t)nd, M_NFSRVDESC);
5139336Sdfr				nd = NULL;
5149336Sdfr			}
5159336Sdfr			nfsd->nfsd_slp = (struct nfssvc_sock *)0;
5169336Sdfr			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
5171541Srgrimes			nfsrv_slpderef(slp);
5181541Srgrimes			continue;
5191541Srgrimes		}
5201541Srgrimes		splx(s);
5211541Srgrimes		so = slp->ns_so;
5221541Srgrimes		sotype = so->so_type;
5231541Srgrimes		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
5241541Srgrimes			solockp = &slp->ns_solock;
5251541Srgrimes		else
5261541Srgrimes			solockp = (int *)0;
5279336Sdfr		if (nd) {
5289336Sdfr		    nd->nd_starttime = time;
5299336Sdfr		    if (nd->nd_nam2)
5309336Sdfr			nd->nd_nam = nd->nd_nam2;
5319336Sdfr		    else
5329336Sdfr			nd->nd_nam = slp->ns_nam;
5331541Srgrimes
5349336Sdfr		    /*
5359336Sdfr		     * Check to see if authorization is needed.
5369336Sdfr		     */
5379336Sdfr		    if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
5389336Sdfr			nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
5399336Sdfr			nsd->nsd_haddr = mtod(nd->nd_nam,
5409336Sdfr			    struct sockaddr_in *)->sin_addr.s_addr;
5419336Sdfr			nsd->nsd_authlen = nfsd->nfsd_authlen;
5429336Sdfr			nsd->nsd_verflen = nfsd->nfsd_verflen;
5439336Sdfr			if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
5449336Sdfr				nfsd->nfsd_authlen) &&
5459336Sdfr			    !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
5469336Sdfr				nfsd->nfsd_verflen) &&
5479336Sdfr			    !copyout((caddr_t)nsd, argp, sizeof (*nsd)))
5489336Sdfr			    return (ENEEDAUTH);
5499336Sdfr			cacherep = RC_DROPIT;
5509336Sdfr		    } else
5519336Sdfr			cacherep = nfsrv_getcache(nd, slp, &mreq);
5521541Srgrimes
5539336Sdfr		    /*
5549336Sdfr		     * Check for just starting up for NQNFS and send
5559336Sdfr		     * fake "try again later" replies to the NQNFS clients.
5569336Sdfr		     */
5579336Sdfr		    if (notstarted && nqnfsstarttime <= time.tv_sec) {
5581541Srgrimes			if (modify_flag) {
5591541Srgrimes				nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
5601541Srgrimes				modify_flag = 0;
5611541Srgrimes			} else
5621541Srgrimes				notstarted = 0;
5639336Sdfr		    }
5649336Sdfr		    if (notstarted) {
5659336Sdfr			if ((nd->nd_flag & ND_NQNFS) == 0)
5661541Srgrimes				cacherep = RC_DROPIT;
5671541Srgrimes			else if (nd->nd_procnum != NFSPROC_WRITE) {
5681541Srgrimes				nd->nd_procnum = NFSPROC_NOOP;
5691541Srgrimes				nd->nd_repstat = NQNFS_TRYLATER;
5701541Srgrimes				cacherep = RC_DOIT;
5711541Srgrimes			} else
5721541Srgrimes				modify_flag = 1;
5739336Sdfr		    } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
5749336Sdfr			nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
5751541Srgrimes			nd->nd_procnum = NFSPROC_NOOP;
5769336Sdfr			nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
5771541Srgrimes			cacherep = RC_DOIT;
5789336Sdfr		    }
5791541Srgrimes		}
5801541Srgrimes
5819336Sdfr		/*
5829336Sdfr		 * Loop to get all the write rpc relies that have been
5839336Sdfr		 * gathered together.
5849336Sdfr		 */
5859336Sdfr		do {
5869336Sdfr		    switch (cacherep) {
5879336Sdfr		    case RC_DOIT:
5889336Sdfr			if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE &&
5899336Sdfr			    nfsrvw_procrastinate > 0 && !notstarted))
5909336Sdfr			    error = nfsrv_writegather(&nd, slp,
5919336Sdfr				nfsd->nfsd_procp, &mreq);
5929336Sdfr			else
5939336Sdfr			    error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
5949336Sdfr				slp, nfsd->nfsd_procp, &mreq);
5959336Sdfr			if (mreq == NULL)
5969336Sdfr				break;
5971541Srgrimes			if (error) {
5981541Srgrimes				if (nd->nd_procnum != NQNFSPROC_VACATED)
5991541Srgrimes					nfsstats.srv_errs++;
6009336Sdfr				nfsrv_updatecache(nd, FALSE, mreq);
6019336Sdfr				if (nd->nd_nam2)
6029336Sdfr					m_freem(nd->nd_nam2);
6031541Srgrimes				break;
6041541Srgrimes			}
6051541Srgrimes			nfsstats.srvrpccnt[nd->nd_procnum]++;
6069336Sdfr			nfsrv_updatecache(nd, TRUE, mreq);
6071541Srgrimes			nd->nd_mrep = (struct mbuf *)0;
6089336Sdfr		    case RC_REPLY:
6091541Srgrimes			m = mreq;
6101541Srgrimes			siz = 0;
6111541Srgrimes			while (m) {
6121541Srgrimes				siz += m->m_len;
6131541Srgrimes				m = m->m_next;
6141541Srgrimes			}
6151541Srgrimes			if (siz <= 0 || siz > NFS_MAXPACKET) {
6161541Srgrimes				printf("mbuf siz=%d\n",siz);
6171541Srgrimes				panic("Bad nfs svc reply");
6181541Srgrimes			}
6191541Srgrimes			m = mreq;
6201541Srgrimes			m->m_pkthdr.len = siz;
6211541Srgrimes			m->m_pkthdr.rcvif = (struct ifnet *)0;
6221541Srgrimes			/*
6231541Srgrimes			 * For stream protocols, prepend a Sun RPC
6241541Srgrimes			 * Record Mark.
6251541Srgrimes			 */
6261541Srgrimes			if (sotype == SOCK_STREAM) {
6271541Srgrimes				M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
6281541Srgrimes				*mtod(m, u_long *) = htonl(0x80000000 | siz);
6291541Srgrimes			}
6301541Srgrimes			if (solockp)
6311541Srgrimes				(void) nfs_sndlock(solockp, (struct nfsreq *)0);
6321541Srgrimes			if (slp->ns_flag & SLP_VALID)
6339336Sdfr			    error = nfs_send(so, nd->nd_nam2, m, NULL);
6341541Srgrimes			else {
6351541Srgrimes			    error = EPIPE;
6361541Srgrimes			    m_freem(m);
6371541Srgrimes			}
6381541Srgrimes			if (nfsrtton)
6399336Sdfr				nfsd_rt(sotype, nd, cacherep);
6409336Sdfr			if (nd->nd_nam2)
6419336Sdfr				MFREE(nd->nd_nam2, m);
6421541Srgrimes			if (nd->nd_mrep)
6431541Srgrimes				m_freem(nd->nd_mrep);
6441541Srgrimes			if (error == EPIPE)
6451541Srgrimes				nfsrv_zapsock(slp);
6461541Srgrimes			if (solockp)
6471541Srgrimes				nfs_sndunlock(solockp);
6481541Srgrimes			if (error == EINTR || error == ERESTART) {
6499336Sdfr				free((caddr_t)nd, M_NFSRVDESC);
6501541Srgrimes				nfsrv_slpderef(slp);
6511541Srgrimes				s = splnet();
6521541Srgrimes				goto done;
6531541Srgrimes			}
6541541Srgrimes			break;
6559336Sdfr		    case RC_DROPIT:
6561541Srgrimes			if (nfsrtton)
6579336Sdfr				nfsd_rt(sotype, nd, cacherep);
6581541Srgrimes			m_freem(nd->nd_mrep);
6599336Sdfr			m_freem(nd->nd_nam2);
6601541Srgrimes			break;
6619336Sdfr		    };
6629336Sdfr		    if (nd) {
6639336Sdfr			FREE((caddr_t)nd, M_NFSRVDESC);
6649336Sdfr			nd = NULL;
6659336Sdfr		    }
6669336Sdfr
6679336Sdfr		    /*
6689336Sdfr		     * Check to see if there are outstanding writes that
6699336Sdfr		     * need to be serviced.
6709336Sdfr		     */
6719336Sdfr		    cur_usec = (u_quad_t)time.tv_sec * 1000000 +
6729336Sdfr			(u_quad_t)time.tv_usec;
6739336Sdfr		    s = splsoftclock();
6749336Sdfr		    if (slp->ns_tq.lh_first &&
6759336Sdfr			slp->ns_tq.lh_first->nd_time <= cur_usec) {
6769336Sdfr			cacherep = RC_DOIT;
6779336Sdfr			writes_todo = 1;
6789336Sdfr		    } else
6799336Sdfr			writes_todo = 0;
6809336Sdfr		    splx(s);
6819336Sdfr		} while (writes_todo);
6821541Srgrimes		s = splnet();
6839336Sdfr		if (nfsrv_dorec(slp, nfsd, &nd)) {
6849336Sdfr			nfsd->nfsd_flag &= ~NFSD_REQINPROG;
6859336Sdfr			nfsd->nfsd_slp = NULL;
6861541Srgrimes			nfsrv_slpderef(slp);
6871541Srgrimes		}
6881541Srgrimes	}
6891541Srgrimesdone:
6909336Sdfr	TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
6911541Srgrimes	splx(s);
6929336Sdfr	free((caddr_t)nfsd, M_NFSD);
6931541Srgrimes	nsd->nsd_nfsd = (struct nfsd *)0;
6941541Srgrimes	if (--nfs_numnfsd == 0)
6951541Srgrimes		nfsrv_init(TRUE);	/* Reinitialize everything */
6961541Srgrimes	return (error);
6971541Srgrimes}
6981541Srgrimes
6991541Srgrimes/*
7001541Srgrimes * Asynchronous I/O daemons for client nfs.
7011541Srgrimes * They do read-ahead and write-behind operations on the block I/O cache.
7021541Srgrimes * Never returns unless it fails or gets killed.
7031541Srgrimes */
7041549Srgrimesint
7051541Srgrimesnfssvc_iod(p)
7061541Srgrimes	struct proc *p;
7071541Srgrimes{
7089336Sdfr	register struct buf *bp, *nbp;
7091541Srgrimes	register int i, myiod;
7109336Sdfr	struct vnode *vp;
7119336Sdfr	int error = 0, s;
7121541Srgrimes
7131541Srgrimes	/*
7141541Srgrimes	 * Assign my position or return error if too many already running
7151541Srgrimes	 */
7161541Srgrimes	myiod = -1;
7171541Srgrimes	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
7181541Srgrimes		if (nfs_asyncdaemon[i] == 0) {
7191541Srgrimes			nfs_asyncdaemon[i]++;
7201541Srgrimes			myiod = i;
7211541Srgrimes			break;
7221541Srgrimes		}
7231541Srgrimes	if (myiod == -1)
7241541Srgrimes		return (EBUSY);
7251541Srgrimes	nfs_numasync++;
7261541Srgrimes	/*
7271541Srgrimes	 * Just loop around doin our stuff until SIGKILL
7281541Srgrimes	 */
7291541Srgrimes	for (;;) {
7309336Sdfr	    while (nfs_bufq.tqh_first == NULL && error == 0) {
7319336Sdfr		nfs_iodwant[myiod] = p;
7329336Sdfr		error = tsleep((caddr_t)&nfs_iodwant[myiod],
7339336Sdfr			PWAIT | PCATCH, "nfsidl", 0);
7349336Sdfr	    }
7359336Sdfr	    while ((bp = nfs_bufq.tqh_first) != NULL) {
7369336Sdfr		/* Take one off the front of the list */
7379336Sdfr		TAILQ_REMOVE(&nfs_bufq, bp, b_freelist);
7389336Sdfr		if (bp->b_flags & B_READ)
7399336Sdfr		    (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
7409336Sdfr		else do {
7419336Sdfr		    /*
7429336Sdfr		     * Look for a delayed write for the same vnode, so I can do
7439336Sdfr		     * it now. We must grab it before calling nfs_doio() to
7449336Sdfr		     * avoid any risk of the vnode getting vclean()'d while
7459336Sdfr		     * we are doing the write rpc.
7469336Sdfr		     */
7479336Sdfr		    vp = bp->b_vp;
7489336Sdfr		    s = splbio();
7499336Sdfr		    for (nbp = vp->v_dirtyblkhd.lh_first; nbp;
7509336Sdfr			nbp = nbp->b_vnbufs.le_next) {
7519336Sdfr			if ((nbp->b_flags &
7529336Sdfr			    (B_BUSY|B_DELWRI|B_NEEDCOMMIT|B_NOCACHE))!=B_DELWRI)
7539336Sdfr			    continue;
7549336Sdfr			bremfree(nbp);
7559336Sdfr			vfs_busy_pages(nbp, 1);
7569336Sdfr			nbp->b_flags |= (B_BUSY|B_ASYNC);
7579336Sdfr			break;
7589336Sdfr		    }
7599336Sdfr		    splx(s);
7609336Sdfr		    /*
7619336Sdfr		     * For the delayed write, do the first part of nfs_bwrite()
7629336Sdfr		     * up to, but not including nfs_strategy().
7639336Sdfr		     */
7649336Sdfr		    if (nbp) {
7659336Sdfr			nbp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
7669336Sdfr			reassignbuf(nbp, nbp->b_vp);
7679336Sdfr			nbp->b_vp->v_numoutput++;
7689336Sdfr		    }
7699336Sdfr		    (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
7709336Sdfr		} while (bp = nbp);
7719336Sdfr	    }
7729336Sdfr	    if (error) {
7739336Sdfr		nfs_asyncdaemon[myiod] = 0;
7749336Sdfr		nfs_numasync--;
7759336Sdfr		return (error);
7769336Sdfr	    }
7771541Srgrimes	}
7781541Srgrimes}
7791541Srgrimes
7801541Srgrimes/*
7811541Srgrimes * Shut down a socket associated with an nfssvc_sock structure.
7821541Srgrimes * Should be called with the send lock set, if required.
7831541Srgrimes * The trick here is to increment the sref at the start, so that the nfsds
7841541Srgrimes * will stop using it and clear ns_flag at the end so that it will not be
7851541Srgrimes * reassigned during cleanup.
7861541Srgrimes */
7871549Srgrimesvoid
7881541Srgrimesnfsrv_zapsock(slp)
7891541Srgrimes	register struct nfssvc_sock *slp;
7901541Srgrimes{
7913664Sphk	register struct nfsuid *nuidp, *nnuidp;
7929336Sdfr	register struct nfsrv_descript *nwp, *nnwp;
7931541Srgrimes	struct socket *so;
7941541Srgrimes	struct file *fp;
7951541Srgrimes	struct mbuf *m;
7969336Sdfr	int s;
7971541Srgrimes
7981541Srgrimes	slp->ns_flag &= ~SLP_ALLFLAGS;
7993305Sphk	fp = slp->ns_fp;
8003305Sphk	if (fp) {
8011541Srgrimes		slp->ns_fp = (struct file *)0;
8021541Srgrimes		so = slp->ns_so;
8031541Srgrimes		so->so_upcall = NULL;
8041541Srgrimes		soshutdown(so, 2);
8051541Srgrimes		closef(fp, (struct proc *)0);
8061541Srgrimes		if (slp->ns_nam)
8071541Srgrimes			MFREE(slp->ns_nam, m);
8081541Srgrimes		m_freem(slp->ns_raw);
8091541Srgrimes		m_freem(slp->ns_rec);
8103664Sphk		for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0;
8113664Sphk		    nuidp = nnuidp) {
8123664Sphk			nnuidp = nuidp->nu_lru.tqe_next;
8133664Sphk			LIST_REMOVE(nuidp, nu_hash);
8143664Sphk			TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
8159336Sdfr			if (nuidp->nu_flag & NU_NAM)
8169336Sdfr				m_freem(nuidp->nu_nam);
8173664Sphk			free((caddr_t)nuidp, M_NFSUID);
8181541Srgrimes		}
8199336Sdfr		s = splsoftclock();
8209336Sdfr		for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
8219336Sdfr			nnwp = nwp->nd_tq.le_next;
8229336Sdfr			LIST_REMOVE(nwp, nd_tq);
8239336Sdfr			free((caddr_t)nwp, M_NFSRVDESC);
8249336Sdfr		}
8259336Sdfr		LIST_INIT(&slp->ns_tq);
8269336Sdfr		splx(s);
8271541Srgrimes	}
8281541Srgrimes}
8291541Srgrimes
8301541Srgrimes/*
8311541Srgrimes * Get an authorization string for the uid by having the mount_nfs sitting
8321541Srgrimes * on this mount point porpous out of the kernel and do it.
8331541Srgrimes */
8341549Srgrimesint
8359336Sdfrnfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
8361541Srgrimes	register struct nfsmount *nmp;
8371541Srgrimes	struct nfsreq *rep;
8381541Srgrimes	struct ucred *cred;
8391541Srgrimes	char **auth_str;
8401541Srgrimes	int *auth_len;
8419336Sdfr	char *verf_str;
8429336Sdfr	int *verf_len;
8439336Sdfr	NFSKERBKEY_T key;		/* return session key */
8441541Srgrimes{
8451541Srgrimes	int error = 0;
8461541Srgrimes
8471541Srgrimes	while ((nmp->nm_flag & NFSMNT_WAITAUTH) == 0) {
8481541Srgrimes		nmp->nm_flag |= NFSMNT_WANTAUTH;
8491541Srgrimes		(void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
8501541Srgrimes			"nfsauth1", 2 * hz);
8513305Sphk		error = nfs_sigintr(nmp, rep, rep->r_procp);
8523305Sphk		if (error) {
8531541Srgrimes			nmp->nm_flag &= ~NFSMNT_WANTAUTH;
8541541Srgrimes			return (error);
8551541Srgrimes		}
8561541Srgrimes	}
8571541Srgrimes	nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
8581541Srgrimes	nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
8599336Sdfr	nmp->nm_authlen = RPCAUTH_MAXSIZ;
8609336Sdfr	nmp->nm_verfstr = verf_str;
8619336Sdfr	nmp->nm_verflen = *verf_len;
8621541Srgrimes	nmp->nm_authuid = cred->cr_uid;
8631541Srgrimes	wakeup((caddr_t)&nmp->nm_authstr);
8641541Srgrimes
8651541Srgrimes	/*
8661541Srgrimes	 * And wait for mount_nfs to do its stuff.
8671541Srgrimes	 */
8681541Srgrimes	while ((nmp->nm_flag & NFSMNT_HASAUTH) == 0 && error == 0) {
8691541Srgrimes		(void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
8701541Srgrimes			"nfsauth2", 2 * hz);
8711541Srgrimes		error = nfs_sigintr(nmp, rep, rep->r_procp);
8721541Srgrimes	}
8731541Srgrimes	if (nmp->nm_flag & NFSMNT_AUTHERR) {
8741541Srgrimes		nmp->nm_flag &= ~NFSMNT_AUTHERR;
8751541Srgrimes		error = EAUTH;
8761541Srgrimes	}
8771541Srgrimes	if (error)
8781541Srgrimes		free((caddr_t)*auth_str, M_TEMP);
8791541Srgrimes	else {
8801541Srgrimes		*auth_len = nmp->nm_authlen;
8819336Sdfr		*verf_len = nmp->nm_verflen;
8829336Sdfr		bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
8831541Srgrimes	}
8841541Srgrimes	nmp->nm_flag &= ~NFSMNT_HASAUTH;
8851541Srgrimes	nmp->nm_flag |= NFSMNT_WAITAUTH;
8861541Srgrimes	if (nmp->nm_flag & NFSMNT_WANTAUTH) {
8871541Srgrimes		nmp->nm_flag &= ~NFSMNT_WANTAUTH;
8881541Srgrimes		wakeup((caddr_t)&nmp->nm_authtype);
8891541Srgrimes	}
8901541Srgrimes	return (error);
8911541Srgrimes}
8921541Srgrimes
8931541Srgrimes/*
8949336Sdfr * Get a nickname authenticator and verifier.
8959336Sdfr */
8969336Sdfrint
8979336Sdfrnfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
8989336Sdfr	struct nfsmount *nmp;
8999336Sdfr	struct ucred *cred;
9009336Sdfr	char **auth_str;
9019336Sdfr	int *auth_len;
9029336Sdfr	char *verf_str;
9039336Sdfr	int verf_len;
9049336Sdfr{
9059336Sdfr	register struct nfsuid *nuidp;
9069336Sdfr	register u_long *nickp, *verfp;
9079336Sdfr	struct timeval ktvin, ktvout;
9089336Sdfr
9099336Sdfr#ifdef DIAGNOSTIC
9109336Sdfr	if (verf_len < (4 * NFSX_UNSIGNED))
9119336Sdfr		panic("nfs_getnickauth verf too small");
9129336Sdfr#endif
9139336Sdfr	for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
9149336Sdfr	    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
9159336Sdfr		if (nuidp->nu_cr.cr_uid == cred->cr_uid)
9169336Sdfr			break;
9179336Sdfr	}
9189336Sdfr	if (!nuidp || nuidp->nu_expire < time.tv_sec)
9199336Sdfr		return (EACCES);
9209336Sdfr
9219336Sdfr	/*
9229336Sdfr	 * Move to the end of the lru list (end of lru == most recently used).
9239336Sdfr	 */
9249336Sdfr	TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
9259336Sdfr	TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
9269336Sdfr
9279336Sdfr	nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
9289336Sdfr	*nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
9299336Sdfr	*nickp = txdr_unsigned(nuidp->nu_nickname);
9309336Sdfr	*auth_str = (char *)nickp;
9319336Sdfr	*auth_len = 2 * NFSX_UNSIGNED;
9329336Sdfr
9339336Sdfr	/*
9349336Sdfr	 * Now we must encrypt the verifier and package it up.
9359336Sdfr	 */
9369336Sdfr	verfp = (u_long *)verf_str;
9379336Sdfr	*verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
9389336Sdfr	if (time.tv_sec > nuidp->nu_timestamp.tv_sec ||
9399336Sdfr	    (time.tv_sec == nuidp->nu_timestamp.tv_sec &&
9409336Sdfr	     time.tv_usec > nuidp->nu_timestamp.tv_usec))
9419336Sdfr		nuidp->nu_timestamp = time;
9429336Sdfr	else
9439336Sdfr		nuidp->nu_timestamp.tv_usec++;
9449336Sdfr	ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
9459336Sdfr	ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
9469336Sdfr
9479336Sdfr	/*
9489336Sdfr	 * Now encrypt the timestamp verifier in ecb mode using the session
9499336Sdfr	 * key.
9509336Sdfr	 */
9519336Sdfr#ifdef NFSKERB
9529336Sdfr	XXX
9539336Sdfr#endif
9549336Sdfr
9559336Sdfr	*verfp++ = ktvout.tv_sec;
9569336Sdfr	*verfp++ = ktvout.tv_usec;
9579336Sdfr	*verfp = 0;
9589336Sdfr	return (0);
9599336Sdfr}
9609336Sdfr
9619336Sdfr/*
9629336Sdfr * Save the current nickname in a hash list entry on the mount point.
9639336Sdfr */
9649336Sdfrint
9659336Sdfrnfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
9669336Sdfr	register struct nfsmount *nmp;
9679336Sdfr	struct ucred *cred;
9689336Sdfr	int len;
9699336Sdfr	NFSKERBKEY_T key;
9709336Sdfr	struct mbuf **mdp;
9719336Sdfr	char **dposp;
9729336Sdfr	struct mbuf *mrep;
9739336Sdfr{
9749336Sdfr	register struct nfsuid *nuidp;
9759336Sdfr	register u_long *tl;
9769336Sdfr	register long t1;
9779336Sdfr	struct mbuf *md = *mdp;
9789336Sdfr	struct timeval ktvin, ktvout;
9799336Sdfr	u_long nick;
9809336Sdfr	char *dpos = *dposp, *cp2;
9819336Sdfr	int deltasec, error = 0;
9829336Sdfr
9839336Sdfr	if (len == (3 * NFSX_UNSIGNED)) {
9849336Sdfr		nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
9859336Sdfr		ktvin.tv_sec = *tl++;
9869336Sdfr		ktvin.tv_usec = *tl++;
9879336Sdfr		nick = fxdr_unsigned(u_long, *tl);
9889336Sdfr
9899336Sdfr		/*
9909336Sdfr		 * Decrypt the timestamp in ecb mode.
9919336Sdfr		 */
9929336Sdfr#ifdef NFSKERB
9939336Sdfr		XXX
9949336Sdfr#endif
9959336Sdfr		ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
9969336Sdfr		ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
9979336Sdfr		deltasec = time.tv_sec - ktvout.tv_sec;
9989336Sdfr		if (deltasec < 0)
9999336Sdfr			deltasec = -deltasec;
10009336Sdfr		/*
10019336Sdfr		 * If ok, add it to the hash list for the mount point.
10029336Sdfr		 */
10039336Sdfr		if (deltasec <= NFS_KERBCLOCKSKEW) {
10049336Sdfr			if (nmp->nm_numuids < nuidhash_max) {
10059336Sdfr				nmp->nm_numuids++;
10069336Sdfr				nuidp = (struct nfsuid *)
10079336Sdfr				   malloc(sizeof (struct nfsuid), M_NFSUID,
10089336Sdfr					M_WAITOK);
10099336Sdfr			} else {
10109336Sdfr				nuidp = nmp->nm_uidlruhead.tqh_first;
10119336Sdfr				LIST_REMOVE(nuidp, nu_hash);
10129336Sdfr				TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
10139336Sdfr					nu_lru);
10149336Sdfr			}
10159336Sdfr			nuidp->nu_flag = 0;
10169336Sdfr			nuidp->nu_cr.cr_uid = cred->cr_uid;
10179336Sdfr			nuidp->nu_expire = time.tv_sec + NFS_KERBTTL;
10189336Sdfr			nuidp->nu_timestamp = ktvout;
10199336Sdfr			nuidp->nu_nickname = nick;
10209336Sdfr			bcopy(key, nuidp->nu_key, sizeof (key));
10219336Sdfr			TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
10229336Sdfr				nu_lru);
10239336Sdfr			LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
10249336Sdfr				nuidp, nu_hash);
10259336Sdfr		}
10269336Sdfr	} else
10279336Sdfr		nfsm_adv(nfsm_rndup(len));
10289336Sdfrnfsmout:
10299336Sdfr	*mdp = md;
10309336Sdfr	*dposp = dpos;
10319336Sdfr	return (error);
10329336Sdfr}
10339336Sdfr
10349336Sdfr/*
10351541Srgrimes * Derefence a server socket structure. If it has no more references and
10361541Srgrimes * is no longer valid, you can throw it away.
10371541Srgrimes */
10381541Srgrimesvoid
10391541Srgrimesnfsrv_slpderef(slp)
10401541Srgrimes	register struct nfssvc_sock *slp;
10411541Srgrimes{
10421541Srgrimes	if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
10433664Sphk		TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
10441541Srgrimes		free((caddr_t)slp, M_NFSSVC);
10451541Srgrimes	}
10461541Srgrimes}
10471541Srgrimes
10481541Srgrimes/*
10491541Srgrimes * Initialize the data structures for the server.
10501541Srgrimes * Handshake with any new nfsds starting up to avoid any chance of
10511541Srgrimes * corruption.
10521541Srgrimes */
10531541Srgrimesvoid
10541541Srgrimesnfsrv_init(terminating)
10551541Srgrimes	int terminating;
10561541Srgrimes{
10573664Sphk	register struct nfssvc_sock *slp, *nslp;
10581541Srgrimes
10593664Sphk	if (nfssvc_sockhead_flag & SLP_INIT)
10601541Srgrimes		panic("nfsd init");
10613664Sphk	nfssvc_sockhead_flag |= SLP_INIT;
10621541Srgrimes	if (terminating) {
10633664Sphk		for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) {
10643664Sphk			nslp = slp->ns_chain.tqe_next;
10651541Srgrimes			if (slp->ns_flag & SLP_VALID)
10661541Srgrimes				nfsrv_zapsock(slp);
10673664Sphk			TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
10683664Sphk			free((caddr_t)slp, M_NFSSVC);
10691541Srgrimes		}
10701541Srgrimes		nfsrv_cleancache();	/* And clear out server cache */
10711541Srgrimes	}
10723664Sphk
10733664Sphk	TAILQ_INIT(&nfssvc_sockhead);
10743664Sphk	nfssvc_sockhead_flag &= ~SLP_INIT;
10753664Sphk	if (nfssvc_sockhead_flag & SLP_WANTINIT) {
10763664Sphk		nfssvc_sockhead_flag &= ~SLP_WANTINIT;
10773664Sphk		wakeup((caddr_t)&nfssvc_sockhead);
10783664Sphk	}
10793664Sphk
10803664Sphk	TAILQ_INIT(&nfsd_head);
10813664Sphk	nfsd_head_flag &= ~NFSD_CHECKSLP;
10823664Sphk
10831541Srgrimes	nfs_udpsock = (struct nfssvc_sock *)
10841541Srgrimes	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
10851541Srgrimes	bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
10863664Sphk	TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
10873664Sphk	TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
10883664Sphk
10891541Srgrimes	nfs_cltpsock = (struct nfssvc_sock *)
10901541Srgrimes	    malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
10911541Srgrimes	bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
10923664Sphk	TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
10933664Sphk	TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
10941541Srgrimes}
10951541Srgrimes
10961541Srgrimes/*
10971541Srgrimes * Add entries to the server monitor log.
10981541Srgrimes */
10991541Srgrimesstatic void
11009336Sdfrnfsd_rt(sotype, nd, cacherep)
11011541Srgrimes	int sotype;
11029336Sdfr	register struct nfsrv_descript *nd;
11031541Srgrimes	int cacherep;
11041541Srgrimes{
11051541Srgrimes	register struct drt *rt;
11061541Srgrimes
11071541Srgrimes	rt = &nfsdrt.drt[nfsdrt.pos];
11081541Srgrimes	if (cacherep == RC_DOIT)
11091541Srgrimes		rt->flag = 0;
11101541Srgrimes	else if (cacherep == RC_REPLY)
11111541Srgrimes		rt->flag = DRT_CACHEREPLY;
11121541Srgrimes	else
11131541Srgrimes		rt->flag = DRT_CACHEDROP;
11141541Srgrimes	if (sotype == SOCK_STREAM)
11151541Srgrimes		rt->flag |= DRT_TCP;
11169336Sdfr	if (nd->nd_flag & ND_NQNFS)
11171541Srgrimes		rt->flag |= DRT_NQNFS;
11189336Sdfr	else if (nd->nd_flag & ND_NFSV3)
11199336Sdfr		rt->flag |= DRT_NFSV3;
11201541Srgrimes	rt->proc = nd->nd_procnum;
11219336Sdfr	if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET)
11229336Sdfr	    rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr;
11231541Srgrimes	else
11249336Sdfr	    rt->ipadr = INADDR_ANY;
11259336Sdfr	rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
11269336Sdfr		(time.tv_usec - nd->nd_starttime.tv_usec);
11271541Srgrimes	rt->tstamp = time;
11281541Srgrimes	nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
11291541Srgrimes}
1130