Home | History | Annotate | Line # | Download | only in nfs
nfs_socket.c revision 1.1.1.2
      1      1.1   cgd /*
      2  1.1.1.2  fvdl  * Copyright (c) 1989, 1991, 1993, 1995
      3  1.1.1.2  fvdl  *	The Regents of the University of California.  All rights reserved.
      4      1.1   cgd  *
      5      1.1   cgd  * This code is derived from software contributed to Berkeley by
      6      1.1   cgd  * Rick Macklem at The University of Guelph.
      7      1.1   cgd  *
      8      1.1   cgd  * Redistribution and use in source and binary forms, with or without
      9      1.1   cgd  * modification, are permitted provided that the following conditions
     10      1.1   cgd  * are met:
     11      1.1   cgd  * 1. Redistributions of source code must retain the above copyright
     12      1.1   cgd  *    notice, this list of conditions and the following disclaimer.
     13      1.1   cgd  * 2. Redistributions in binary form must reproduce the above copyright
     14      1.1   cgd  *    notice, this list of conditions and the following disclaimer in the
     15      1.1   cgd  *    documentation and/or other materials provided with the distribution.
     16      1.1   cgd  * 3. All advertising materials mentioning features or use of this software
     17      1.1   cgd  *    must display the following acknowledgement:
     18      1.1   cgd  *	This product includes software developed by the University of
     19      1.1   cgd  *	California, Berkeley and its contributors.
     20      1.1   cgd  * 4. Neither the name of the University nor the names of its contributors
     21      1.1   cgd  *    may be used to endorse or promote products derived from this software
     22      1.1   cgd  *    without specific prior written permission.
     23      1.1   cgd  *
     24      1.1   cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25      1.1   cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26      1.1   cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27      1.1   cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28      1.1   cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29      1.1   cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30      1.1   cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31      1.1   cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32      1.1   cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33      1.1   cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34      1.1   cgd  * SUCH DAMAGE.
     35      1.1   cgd  *
     36  1.1.1.2  fvdl  *	@(#)nfs_socket.c	8.5 (Berkeley) 3/30/95
     37      1.1   cgd  */
     38      1.1   cgd 
     39      1.1   cgd /*
     40      1.1   cgd  * Socket operations for use by nfs
     41      1.1   cgd  */
     42      1.1   cgd 
     43  1.1.1.2  fvdl #include <sys/param.h>
     44  1.1.1.2  fvdl #include <sys/systm.h>
     45  1.1.1.2  fvdl #include <sys/proc.h>
     46  1.1.1.2  fvdl #include <sys/mount.h>
     47  1.1.1.2  fvdl #include <sys/kernel.h>
     48  1.1.1.2  fvdl #include <sys/mbuf.h>
     49  1.1.1.2  fvdl #include <sys/vnode.h>
     50  1.1.1.2  fvdl #include <sys/domain.h>
     51  1.1.1.2  fvdl #include <sys/protosw.h>
     52  1.1.1.2  fvdl #include <sys/socket.h>
     53  1.1.1.2  fvdl #include <sys/socketvar.h>
     54  1.1.1.2  fvdl #include <sys/syslog.h>
     55  1.1.1.2  fvdl #include <sys/tprintf.h>
     56  1.1.1.2  fvdl 
     57  1.1.1.2  fvdl #include <netinet/in.h>
     58  1.1.1.2  fvdl #include <netinet/tcp.h>
     59  1.1.1.2  fvdl 
     60  1.1.1.2  fvdl #include <nfs/rpcv2.h>
     61  1.1.1.2  fvdl #include <nfs/nfsproto.h>
     62  1.1.1.2  fvdl #include <nfs/nfs.h>
     63  1.1.1.2  fvdl #include <nfs/xdr_subs.h>
     64  1.1.1.2  fvdl #include <nfs/nfsm_subs.h>
     65  1.1.1.2  fvdl #include <nfs/nfsmount.h>
     66  1.1.1.2  fvdl #include <nfs/nfsnode.h>
     67  1.1.1.2  fvdl #include <nfs/nfsrtt.h>
     68  1.1.1.2  fvdl #include <nfs/nqnfs.h>
     69      1.1   cgd 
     70      1.1   cgd #define	TRUE	1
     71      1.1   cgd #define	FALSE	0
     72      1.1   cgd 
     73      1.1   cgd /*
     74  1.1.1.2  fvdl  * Estimate rto for an nfs rpc sent via. an unreliable datagram.
     75  1.1.1.2  fvdl  * Use the mean and mean deviation of rtt for the appropriate type of rpc
     76  1.1.1.2  fvdl  * for the frequent rpcs and a default for the others.
     77  1.1.1.2  fvdl  * The justification for doing "other" this way is that these rpcs
     78  1.1.1.2  fvdl  * happen so infrequently that timer est. would probably be stale.
     79  1.1.1.2  fvdl  * Also, since many of these rpcs are
     80  1.1.1.2  fvdl  * non-idempotent, a conservative timeout is desired.
     81  1.1.1.2  fvdl  * getattr, lookup - A+2D
     82  1.1.1.2  fvdl  * read, write     - A+4D
     83  1.1.1.2  fvdl  * other           - nm_timeo
     84  1.1.1.2  fvdl  */
     85  1.1.1.2  fvdl #define	NFS_RTO(n, t) \
     86  1.1.1.2  fvdl 	((t) == 0 ? (n)->nm_timeo : \
     87  1.1.1.2  fvdl 	 ((t) < 3 ? \
     88  1.1.1.2  fvdl 	  (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \
     89  1.1.1.2  fvdl 	  ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1)))
     90  1.1.1.2  fvdl #define	NFS_SRTT(r)	(r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1]
     91  1.1.1.2  fvdl #define	NFS_SDRTT(r)	(r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1]
     92  1.1.1.2  fvdl /*
     93      1.1   cgd  * External data, mostly RPC constants in XDR form
     94      1.1   cgd  */
     95      1.1   cgd extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
     96  1.1.1.2  fvdl 	rpc_msgaccepted, rpc_call, rpc_autherr,
     97  1.1.1.2  fvdl 	rpc_auth_kerb;
     98  1.1.1.2  fvdl extern u_long nfs_prog, nqnfs_prog;
     99  1.1.1.2  fvdl extern time_t nqnfsstarttime;
    100  1.1.1.2  fvdl extern struct nfsstats nfsstats;
    101  1.1.1.2  fvdl extern int nfsv3_procid[NFS_NPROCS];
    102  1.1.1.2  fvdl extern int nfs_ticks;
    103  1.1.1.2  fvdl 
    104  1.1.1.2  fvdl /*
    105  1.1.1.2  fvdl  * Defines which timer to use for the procnum.
    106  1.1.1.2  fvdl  * 0 - default
    107  1.1.1.2  fvdl  * 1 - getattr
    108  1.1.1.2  fvdl  * 2 - lookup
    109  1.1.1.2  fvdl  * 3 - read
    110  1.1.1.2  fvdl  * 4 - write
    111  1.1.1.2  fvdl  */
    112  1.1.1.2  fvdl static int proct[NFS_NPROCS] = {
    113  1.1.1.2  fvdl 	0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0,
    114  1.1.1.2  fvdl 	0, 0, 0,
    115      1.1   cgd };
    116  1.1.1.2  fvdl 
    117  1.1.1.2  fvdl /*
    118  1.1.1.2  fvdl  * There is a congestion window for outstanding rpcs maintained per mount
    119  1.1.1.2  fvdl  * point. The cwnd size is adjusted in roughly the way that:
    120  1.1.1.2  fvdl  * Van Jacobson, Congestion avoidance and Control, In "Proceedings of
    121  1.1.1.2  fvdl  * SIGCOMM '88". ACM, August 1988.
    122  1.1.1.2  fvdl  * describes for TCP. The cwnd size is chopped in half on a retransmit timeout
    123  1.1.1.2  fvdl  * and incremented by 1/cwnd when each rpc reply is received and a full cwnd
    124  1.1.1.2  fvdl  * of rpcs is in progress.
    125  1.1.1.2  fvdl  * (The sent count and cwnd are scaled for integer arith.)
    126  1.1.1.2  fvdl  * Variants of "slow start" were tried and were found to be too much of a
    127  1.1.1.2  fvdl  * performance hit (ave. rtt 3 times larger),
    128  1.1.1.2  fvdl  * I suspect due to the large rtt that nfs rpcs have.
    129  1.1.1.2  fvdl  */
    130  1.1.1.2  fvdl #define	NFS_CWNDSCALE	256
    131  1.1.1.2  fvdl #define	NFS_MAXCWND	(NFS_CWNDSCALE * 32)
    132  1.1.1.2  fvdl static int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };
    133      1.1   cgd int	nfs_sbwait();
    134  1.1.1.2  fvdl void	nfs_disconnect(), nfs_realign(), nfsrv_wakenfsd(), nfs_sndunlock();
    135  1.1.1.2  fvdl void	nfs_rcvunlock(), nqnfs_serverd(), nqnfs_clientlease();
    136  1.1.1.2  fvdl struct mbuf *nfsm_rpchead();
    137  1.1.1.2  fvdl int nfsrtton = 0;
    138  1.1.1.2  fvdl struct nfsrtt nfsrtt;
    139      1.1   cgd 
    140      1.1   cgd int	nfsrv_null(),
    141      1.1   cgd 	nfsrv_getattr(),
    142      1.1   cgd 	nfsrv_setattr(),
    143      1.1   cgd 	nfsrv_lookup(),
    144  1.1.1.2  fvdl 	nfsrv3_access(),
    145      1.1   cgd 	nfsrv_readlink(),
    146      1.1   cgd 	nfsrv_read(),
    147      1.1   cgd 	nfsrv_write(),
    148      1.1   cgd 	nfsrv_create(),
    149  1.1.1.2  fvdl 	nfsrv_mknod(),
    150      1.1   cgd 	nfsrv_remove(),
    151      1.1   cgd 	nfsrv_rename(),
    152      1.1   cgd 	nfsrv_link(),
    153      1.1   cgd 	nfsrv_symlink(),
    154      1.1   cgd 	nfsrv_mkdir(),
    155      1.1   cgd 	nfsrv_rmdir(),
    156      1.1   cgd 	nfsrv_readdir(),
    157  1.1.1.2  fvdl 	nfsrv_readdirplus(),
    158      1.1   cgd 	nfsrv_statfs(),
    159  1.1.1.2  fvdl 	nfsrv_fsinfo(),
    160  1.1.1.2  fvdl 	nfsrv_pathconf(),
    161  1.1.1.2  fvdl 	nfsrv_commit(),
    162  1.1.1.2  fvdl 	nfsrv_noop(),
    163  1.1.1.2  fvdl 	nqnfsrv_getlease(),
    164  1.1.1.2  fvdl 	nqnfsrv_vacated();
    165      1.1   cgd 
    166  1.1.1.2  fvdl int (*nfsrv3_procs[NFS_NPROCS])() = {
    167      1.1   cgd 	nfsrv_null,
    168      1.1   cgd 	nfsrv_getattr,
    169      1.1   cgd 	nfsrv_setattr,
    170      1.1   cgd 	nfsrv_lookup,
    171  1.1.1.2  fvdl 	nfsrv3_access,
    172      1.1   cgd 	nfsrv_readlink,
    173      1.1   cgd 	nfsrv_read,
    174      1.1   cgd 	nfsrv_write,
    175      1.1   cgd 	nfsrv_create,
    176  1.1.1.2  fvdl 	nfsrv_mkdir,
    177  1.1.1.2  fvdl 	nfsrv_symlink,
    178  1.1.1.2  fvdl 	nfsrv_mknod,
    179      1.1   cgd 	nfsrv_remove,
    180  1.1.1.2  fvdl 	nfsrv_rmdir,
    181      1.1   cgd 	nfsrv_rename,
    182      1.1   cgd 	nfsrv_link,
    183      1.1   cgd 	nfsrv_readdir,
    184  1.1.1.2  fvdl 	nfsrv_readdirplus,
    185      1.1   cgd 	nfsrv_statfs,
    186  1.1.1.2  fvdl 	nfsrv_fsinfo,
    187  1.1.1.2  fvdl 	nfsrv_pathconf,
    188  1.1.1.2  fvdl 	nfsrv_commit,
    189  1.1.1.2  fvdl 	nqnfsrv_getlease,
    190  1.1.1.2  fvdl 	nqnfsrv_vacated,
    191  1.1.1.2  fvdl 	nfsrv_noop,
    192  1.1.1.2  fvdl 	nfsrv_noop
    193      1.1   cgd };
    194      1.1   cgd 
    195      1.1   cgd /*
    196      1.1   cgd  * Initialize sockets and congestion for a new NFS connection.
    197      1.1   cgd  * We do not free the sockaddr if error.
    198      1.1   cgd  */
    199  1.1.1.2  fvdl int
    200  1.1.1.2  fvdl nfs_connect(nmp, rep)
    201      1.1   cgd 	register struct nfsmount *nmp;
    202  1.1.1.2  fvdl 	struct nfsreq *rep;
    203      1.1   cgd {
    204      1.1   cgd 	register struct socket *so;
    205  1.1.1.2  fvdl 	int s, error, rcvreserve, sndreserve;
    206  1.1.1.2  fvdl 	struct sockaddr *saddr;
    207  1.1.1.2  fvdl 	struct sockaddr_in *sin;
    208      1.1   cgd 	struct mbuf *m;
    209  1.1.1.2  fvdl 	u_short tport;
    210      1.1   cgd 
    211      1.1   cgd 	nmp->nm_so = (struct socket *)0;
    212  1.1.1.2  fvdl 	saddr = mtod(nmp->nm_nam, struct sockaddr *);
    213  1.1.1.2  fvdl 	error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype,
    214  1.1.1.2  fvdl 		nmp->nm_soproto);
    215  1.1.1.2  fvdl 	if (error)
    216      1.1   cgd 		goto bad;
    217      1.1   cgd 	so = nmp->nm_so;
    218      1.1   cgd 	nmp->nm_soflags = so->so_proto->pr_flags;
    219      1.1   cgd 
    220  1.1.1.2  fvdl 	/*
    221  1.1.1.2  fvdl 	 * Some servers require that the client port be a reserved port number.
    222  1.1.1.2  fvdl 	 */
    223  1.1.1.2  fvdl 	if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) {
    224  1.1.1.2  fvdl 		MGET(m, M_WAIT, MT_SONAME);
    225  1.1.1.2  fvdl 		sin = mtod(m, struct sockaddr_in *);
    226  1.1.1.2  fvdl 		sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
    227  1.1.1.2  fvdl 		sin->sin_family = AF_INET;
    228  1.1.1.2  fvdl 		sin->sin_addr.s_addr = INADDR_ANY;
    229  1.1.1.2  fvdl 		tport = IPPORT_RESERVED - 1;
    230  1.1.1.2  fvdl 		sin->sin_port = htons(tport);
    231  1.1.1.2  fvdl 		while ((error = sobind(so, m)) == EADDRINUSE &&
    232  1.1.1.2  fvdl 		       --tport > IPPORT_RESERVED / 2)
    233  1.1.1.2  fvdl 			sin->sin_port = htons(tport);
    234  1.1.1.2  fvdl 		m_freem(m);
    235  1.1.1.2  fvdl 		if (error)
    236  1.1.1.2  fvdl 			goto bad;
    237  1.1.1.2  fvdl 	}
    238      1.1   cgd 
    239      1.1   cgd 	/*
    240      1.1   cgd 	 * Protocols that do not require connections may be optionally left
    241      1.1   cgd 	 * unconnected for servers that reply from a port other than NFS_PORT.
    242      1.1   cgd 	 */
    243      1.1   cgd 	if (nmp->nm_flag & NFSMNT_NOCONN) {
    244      1.1   cgd 		if (nmp->nm_soflags & PR_CONNREQUIRED) {
    245      1.1   cgd 			error = ENOTCONN;
    246      1.1   cgd 			goto bad;
    247      1.1   cgd 		}
    248      1.1   cgd 	} else {
    249  1.1.1.2  fvdl 		error = soconnect(so, nmp->nm_nam);
    250  1.1.1.2  fvdl 		if (error)
    251      1.1   cgd 			goto bad;
    252      1.1   cgd 
    253      1.1   cgd 		/*
    254      1.1   cgd 		 * Wait for the connection to complete. Cribbed from the
    255  1.1.1.2  fvdl 		 * connect system call but with the wait timing out so
    256  1.1.1.2  fvdl 		 * that interruptible mounts don't hang here for a long time.
    257      1.1   cgd 		 */
    258      1.1   cgd 		s = splnet();
    259  1.1.1.2  fvdl 		while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
    260  1.1.1.2  fvdl 			(void) tsleep((caddr_t)&so->so_timeo, PSOCK,
    261  1.1.1.2  fvdl 				"nfscon", 2 * hz);
    262  1.1.1.2  fvdl 			if ((so->so_state & SS_ISCONNECTING) &&
    263  1.1.1.2  fvdl 			    so->so_error == 0 && rep &&
    264  1.1.1.2  fvdl 			    (error = nfs_sigintr(nmp, rep, rep->r_procp))) {
    265  1.1.1.2  fvdl 				so->so_state &= ~SS_ISCONNECTING;
    266  1.1.1.2  fvdl 				splx(s);
    267  1.1.1.2  fvdl 				goto bad;
    268  1.1.1.2  fvdl 			}
    269  1.1.1.2  fvdl 		}
    270      1.1   cgd 		if (so->so_error) {
    271      1.1   cgd 			error = so->so_error;
    272  1.1.1.2  fvdl 			so->so_error = 0;
    273  1.1.1.2  fvdl 			splx(s);
    274      1.1   cgd 			goto bad;
    275      1.1   cgd 		}
    276  1.1.1.2  fvdl 		splx(s);
    277  1.1.1.2  fvdl 	}
    278  1.1.1.2  fvdl 	if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) {
    279  1.1.1.2  fvdl 		so->so_rcv.sb_timeo = (5 * hz);
    280  1.1.1.2  fvdl 		so->so_snd.sb_timeo = (5 * hz);
    281  1.1.1.2  fvdl 	} else {
    282  1.1.1.2  fvdl 		so->so_rcv.sb_timeo = 0;
    283  1.1.1.2  fvdl 		so->so_snd.sb_timeo = 0;
    284      1.1   cgd 	}
    285      1.1   cgd 	if (nmp->nm_sotype == SOCK_DGRAM) {
    286  1.1.1.2  fvdl 		sndreserve = nmp->nm_wsize + NFS_MAXPKTHDR;
    287  1.1.1.2  fvdl 		rcvreserve = nmp->nm_rsize + NFS_MAXPKTHDR;
    288  1.1.1.2  fvdl 	} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
    289  1.1.1.2  fvdl 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2;
    290  1.1.1.2  fvdl 		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2;
    291      1.1   cgd 	} else {
    292  1.1.1.2  fvdl 		if (nmp->nm_sotype != SOCK_STREAM)
    293  1.1.1.2  fvdl 			panic("nfscon sotype");
    294      1.1   cgd 		if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
    295      1.1   cgd 			MGET(m, M_WAIT, MT_SOOPTS);
    296      1.1   cgd 			*mtod(m, int *) = 1;
    297      1.1   cgd 			m->m_len = sizeof(int);
    298      1.1   cgd 			sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
    299      1.1   cgd 		}
    300  1.1.1.2  fvdl 		if (so->so_proto->pr_protocol == IPPROTO_TCP) {
    301      1.1   cgd 			MGET(m, M_WAIT, MT_SOOPTS);
    302      1.1   cgd 			*mtod(m, int *) = 1;
    303      1.1   cgd 			m->m_len = sizeof(int);
    304      1.1   cgd 			sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
    305      1.1   cgd 		}
    306  1.1.1.2  fvdl 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof (u_long))
    307  1.1.1.2  fvdl 				* 2;
    308  1.1.1.2  fvdl 		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + sizeof (u_long))
    309  1.1.1.2  fvdl 				* 2;
    310      1.1   cgd 	}
    311  1.1.1.2  fvdl 	error = soreserve(so, sndreserve, rcvreserve);
    312  1.1.1.2  fvdl 	if (error)
    313  1.1.1.2  fvdl 		goto bad;
    314      1.1   cgd 	so->so_rcv.sb_flags |= SB_NOINTR;
    315      1.1   cgd 	so->so_snd.sb_flags |= SB_NOINTR;
    316      1.1   cgd 
    317      1.1   cgd 	/* Initialize other non-zero congestion variables */
    318  1.1.1.2  fvdl 	nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] =
    319  1.1.1.2  fvdl 		nmp->nm_srtt[4] = (NFS_TIMEO << 3);
    320  1.1.1.2  fvdl 	nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] =
    321  1.1.1.2  fvdl 		nmp->nm_sdrtt[3] = nmp->nm_sdrtt[4] = 0;
    322  1.1.1.2  fvdl 	nmp->nm_cwnd = NFS_MAXCWND / 2;	    /* Initial send window */
    323      1.1   cgd 	nmp->nm_sent = 0;
    324  1.1.1.2  fvdl 	nmp->nm_timeouts = 0;
    325      1.1   cgd 	return (0);
    326      1.1   cgd 
    327      1.1   cgd bad:
    328      1.1   cgd 	nfs_disconnect(nmp);
    329      1.1   cgd 	return (error);
    330      1.1   cgd }
    331      1.1   cgd 
    332      1.1   cgd /*
    333      1.1   cgd  * Reconnect routine:
    334      1.1   cgd  * Called when a connection is broken on a reliable protocol.
    335      1.1   cgd  * - clean up the old socket
    336      1.1   cgd  * - nfs_connect() again
    337      1.1   cgd  * - set R_MUSTRESEND for all outstanding requests on mount point
    338      1.1   cgd  * If this fails the mount point is DEAD!
    339  1.1.1.2  fvdl  * nb: Must be called with the nfs_sndlock() set on the mount point.
    340      1.1   cgd  */
    341  1.1.1.2  fvdl int
    342  1.1.1.2  fvdl nfs_reconnect(rep)
    343      1.1   cgd 	register struct nfsreq *rep;
    344      1.1   cgd {
    345      1.1   cgd 	register struct nfsreq *rp;
    346  1.1.1.2  fvdl 	register struct nfsmount *nmp = rep->r_nmp;
    347      1.1   cgd 	int error;
    348      1.1   cgd 
    349  1.1.1.2  fvdl 	nfs_disconnect(nmp);
    350  1.1.1.2  fvdl 	while ((error = nfs_connect(nmp, rep))) {
    351  1.1.1.2  fvdl 		if (error == EINTR || error == ERESTART)
    352      1.1   cgd 			return (EINTR);
    353      1.1   cgd 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0);
    354      1.1   cgd 	}
    355      1.1   cgd 
    356      1.1   cgd 	/*
    357      1.1   cgd 	 * Loop through outstanding request list and fix up all requests
    358      1.1   cgd 	 * on old socket.
    359      1.1   cgd 	 */
    360  1.1.1.2  fvdl 	for (rp = nfs_reqq.tqh_first; rp != 0; rp = rp->r_chain.tqe_next) {
    361      1.1   cgd 		if (rp->r_nmp == nmp)
    362      1.1   cgd 			rp->r_flags |= R_MUSTRESEND;
    363      1.1   cgd 	}
    364      1.1   cgd 	return (0);
    365      1.1   cgd }
    366      1.1   cgd 
    367      1.1   cgd /*
    368      1.1   cgd  * NFS disconnect. Clean up and unlink.
    369      1.1   cgd  */
    370      1.1   cgd void
    371      1.1   cgd nfs_disconnect(nmp)
    372      1.1   cgd 	register struct nfsmount *nmp;
    373      1.1   cgd {
    374      1.1   cgd 	register struct socket *so;
    375      1.1   cgd 
    376      1.1   cgd 	if (nmp->nm_so) {
    377      1.1   cgd 		so = nmp->nm_so;
    378      1.1   cgd 		nmp->nm_so = (struct socket *)0;
    379      1.1   cgd 		soshutdown(so, 2);
    380      1.1   cgd 		soclose(so);
    381      1.1   cgd 	}
    382      1.1   cgd }
    383      1.1   cgd 
    384      1.1   cgd /*
    385      1.1   cgd  * This is the nfs send routine. For connection based socket types, it
    386  1.1.1.2  fvdl  * must be called with an nfs_sndlock() on the socket.
    387      1.1   cgd  * "rep == NULL" indicates that it has been called from a server.
    388  1.1.1.2  fvdl  * For the client side:
    389  1.1.1.2  fvdl  * - return EINTR if the RPC is terminated, 0 otherwise
    390  1.1.1.2  fvdl  * - set R_MUSTRESEND if the send fails for any reason
    391  1.1.1.2  fvdl  * - do any cleanup required by recoverable socket errors (???)
    392  1.1.1.2  fvdl  * For the server side:
    393  1.1.1.2  fvdl  * - return EINTR or ERESTART if interrupted by a signal
    394  1.1.1.2  fvdl  * - return EPIPE if a connection is lost for connection based sockets (TCP...)
    395  1.1.1.2  fvdl  * - do any cleanup required by recoverable socket errors (???)
    396      1.1   cgd  */
    397  1.1.1.2  fvdl int
    398      1.1   cgd nfs_send(so, nam, top, rep)
    399      1.1   cgd 	register struct socket *so;
    400      1.1   cgd 	struct mbuf *nam;
    401      1.1   cgd 	register struct mbuf *top;
    402      1.1   cgd 	struct nfsreq *rep;
    403      1.1   cgd {
    404      1.1   cgd 	struct mbuf *sendnam;
    405  1.1.1.2  fvdl 	int error, soflags, flags;
    406      1.1   cgd 
    407      1.1   cgd 	if (rep) {
    408      1.1   cgd 		if (rep->r_flags & R_SOFTTERM) {
    409      1.1   cgd 			m_freem(top);
    410      1.1   cgd 			return (EINTR);
    411      1.1   cgd 		}
    412  1.1.1.2  fvdl 		if ((so = rep->r_nmp->nm_so) == NULL) {
    413  1.1.1.2  fvdl 			rep->r_flags |= R_MUSTRESEND;
    414  1.1.1.2  fvdl 			m_freem(top);
    415  1.1.1.2  fvdl 			return (0);
    416  1.1.1.2  fvdl 		}
    417      1.1   cgd 		rep->r_flags &= ~R_MUSTRESEND;
    418      1.1   cgd 		soflags = rep->r_nmp->nm_soflags;
    419      1.1   cgd 	} else
    420      1.1   cgd 		soflags = so->so_proto->pr_flags;
    421      1.1   cgd 	if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
    422      1.1   cgd 		sendnam = (struct mbuf *)0;
    423      1.1   cgd 	else
    424      1.1   cgd 		sendnam = nam;
    425  1.1.1.2  fvdl 	if (so->so_type == SOCK_SEQPACKET)
    426  1.1.1.2  fvdl 		flags = MSG_EOR;
    427  1.1.1.2  fvdl 	else
    428  1.1.1.2  fvdl 		flags = 0;
    429      1.1   cgd 
    430      1.1   cgd 	error = sosend(so, sendnam, (struct uio *)0, top,
    431  1.1.1.2  fvdl 		(struct mbuf *)0, flags);
    432  1.1.1.2  fvdl 	if (error) {
    433  1.1.1.2  fvdl 		if (rep) {
    434  1.1.1.2  fvdl 			log(LOG_INFO, "nfs send error %d for server %s\n",error,
    435  1.1.1.2  fvdl 			    rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    436  1.1.1.2  fvdl 			/*
    437  1.1.1.2  fvdl 			 * Deal with errors for the client side.
    438  1.1.1.2  fvdl 			 */
    439  1.1.1.2  fvdl 			if (rep->r_flags & R_SOFTTERM)
    440  1.1.1.2  fvdl 				error = EINTR;
    441  1.1.1.2  fvdl 			else
    442  1.1.1.2  fvdl 				rep->r_flags |= R_MUSTRESEND;
    443  1.1.1.2  fvdl 		} else
    444  1.1.1.2  fvdl 			log(LOG_INFO, "nfsd send error %d\n", error);
    445  1.1.1.2  fvdl 
    446  1.1.1.2  fvdl 		/*
    447  1.1.1.2  fvdl 		 * Handle any recoverable (soft) socket errors here. (???)
    448  1.1.1.2  fvdl 		 */
    449  1.1.1.2  fvdl 		if (error != EINTR && error != ERESTART &&
    450  1.1.1.2  fvdl 			error != EWOULDBLOCK && error != EPIPE)
    451      1.1   cgd 			error = 0;
    452      1.1   cgd 	}
    453      1.1   cgd 	return (error);
    454      1.1   cgd }
    455      1.1   cgd 
    456      1.1   cgd /*
    457      1.1   cgd  * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
    458      1.1   cgd  * done by soreceive(), but for SOCK_STREAM we must deal with the Record
    459      1.1   cgd  * Mark and consolidate the data into a new mbuf list.
    460      1.1   cgd  * nb: Sometimes TCP passes the data up to soreceive() in long lists of
    461      1.1   cgd  *     small mbufs.
    462      1.1   cgd  * For SOCK_STREAM we must be very careful to read an entire record once
    463      1.1   cgd  * we have read any of it, even if the system call has been interrupted.
    464      1.1   cgd  */
    465  1.1.1.2  fvdl int
    466  1.1.1.2  fvdl nfs_receive(rep, aname, mp)
    467  1.1.1.2  fvdl 	register struct nfsreq *rep;
    468      1.1   cgd 	struct mbuf **aname;
    469      1.1   cgd 	struct mbuf **mp;
    470      1.1   cgd {
    471  1.1.1.2  fvdl 	register struct socket *so;
    472      1.1   cgd 	struct uio auio;
    473      1.1   cgd 	struct iovec aio;
    474      1.1   cgd 	register struct mbuf *m;
    475  1.1.1.2  fvdl 	struct mbuf *control;
    476      1.1   cgd 	u_long len;
    477      1.1   cgd 	struct mbuf **getnam;
    478  1.1.1.2  fvdl 	int error, sotype, rcvflg;
    479  1.1.1.2  fvdl 	struct proc *p = curproc;	/* XXX */
    480      1.1   cgd 
    481      1.1   cgd 	/*
    482      1.1   cgd 	 * Set up arguments for soreceive()
    483      1.1   cgd 	 */
    484      1.1   cgd 	*mp = (struct mbuf *)0;
    485      1.1   cgd 	*aname = (struct mbuf *)0;
    486  1.1.1.2  fvdl 	sotype = rep->r_nmp->nm_sotype;
    487      1.1   cgd 
    488      1.1   cgd 	/*
    489      1.1   cgd 	 * For reliable protocols, lock against other senders/receivers
    490      1.1   cgd 	 * in case a reconnect is necessary.
    491      1.1   cgd 	 * For SOCK_STREAM, first get the Record Mark to find out how much
    492      1.1   cgd 	 * more there is to get.
    493      1.1   cgd 	 * We must lock the socket against other receivers
    494      1.1   cgd 	 * until we have an entire rpc request/reply.
    495      1.1   cgd 	 */
    496  1.1.1.2  fvdl 	if (sotype != SOCK_DGRAM) {
    497  1.1.1.2  fvdl 		error = nfs_sndlock(&rep->r_nmp->nm_flag, rep);
    498  1.1.1.2  fvdl 		if (error)
    499  1.1.1.2  fvdl 			return (error);
    500      1.1   cgd tryagain:
    501      1.1   cgd 		/*
    502      1.1   cgd 		 * Check for fatal errors and resending request.
    503      1.1   cgd 		 */
    504  1.1.1.2  fvdl 		/*
    505  1.1.1.2  fvdl 		 * Ugh: If a reconnect attempt just happened, nm_so
    506  1.1.1.2  fvdl 		 * would have changed. NULL indicates a failed
    507  1.1.1.2  fvdl 		 * attempt that has essentially shut down this
    508  1.1.1.2  fvdl 		 * mount point.
    509  1.1.1.2  fvdl 		 */
    510  1.1.1.2  fvdl 		if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) {
    511  1.1.1.2  fvdl 			nfs_sndunlock(&rep->r_nmp->nm_flag);
    512  1.1.1.2  fvdl 			return (EINTR);
    513  1.1.1.2  fvdl 		}
    514  1.1.1.2  fvdl 		so = rep->r_nmp->nm_so;
    515  1.1.1.2  fvdl 		if (!so) {
    516  1.1.1.2  fvdl 			error = nfs_reconnect(rep);
    517  1.1.1.2  fvdl 			if (error) {
    518  1.1.1.2  fvdl 				nfs_sndunlock(&rep->r_nmp->nm_flag);
    519  1.1.1.2  fvdl 				return (error);
    520  1.1.1.2  fvdl 			}
    521  1.1.1.2  fvdl 			goto tryagain;
    522  1.1.1.2  fvdl 		}
    523  1.1.1.2  fvdl 		while (rep->r_flags & R_MUSTRESEND) {
    524  1.1.1.2  fvdl 			m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
    525  1.1.1.2  fvdl 			nfsstats.rpcretries++;
    526  1.1.1.2  fvdl 			error = nfs_send(so, rep->r_nmp->nm_nam, m, rep);
    527  1.1.1.2  fvdl 			if (error) {
    528  1.1.1.2  fvdl 				if (error == EINTR || error == ERESTART ||
    529  1.1.1.2  fvdl 				    (error = nfs_reconnect(rep))) {
    530  1.1.1.2  fvdl 					nfs_sndunlock(&rep->r_nmp->nm_flag);
    531  1.1.1.2  fvdl 					return (error);
    532  1.1.1.2  fvdl 				}
    533  1.1.1.2  fvdl 				goto tryagain;
    534      1.1   cgd 			}
    535      1.1   cgd 		}
    536  1.1.1.2  fvdl 		nfs_sndunlock(&rep->r_nmp->nm_flag);
    537  1.1.1.2  fvdl 		if (sotype == SOCK_STREAM) {
    538      1.1   cgd 			aio.iov_base = (caddr_t) &len;
    539      1.1   cgd 			aio.iov_len = sizeof(u_long);
    540      1.1   cgd 			auio.uio_iov = &aio;
    541      1.1   cgd 			auio.uio_iovcnt = 1;
    542      1.1   cgd 			auio.uio_segflg = UIO_SYSSPACE;
    543      1.1   cgd 			auio.uio_rw = UIO_READ;
    544      1.1   cgd 			auio.uio_offset = 0;
    545      1.1   cgd 			auio.uio_resid = sizeof(u_long);
    546  1.1.1.2  fvdl 			auio.uio_procp = p;
    547      1.1   cgd 			do {
    548  1.1.1.2  fvdl 			   rcvflg = MSG_WAITALL;
    549  1.1.1.2  fvdl 			   error = soreceive(so, (struct mbuf **)0, &auio,
    550      1.1   cgd 				(struct mbuf **)0, (struct mbuf **)0, &rcvflg);
    551  1.1.1.2  fvdl 			   if (error == EWOULDBLOCK && rep) {
    552      1.1   cgd 				if (rep->r_flags & R_SOFTTERM)
    553      1.1   cgd 					return (EINTR);
    554  1.1.1.2  fvdl 			   }
    555      1.1   cgd 			} while (error == EWOULDBLOCK);
    556      1.1   cgd 			if (!error && auio.uio_resid > 0) {
    557  1.1.1.2  fvdl 			    log(LOG_INFO,
    558  1.1.1.2  fvdl 				 "short receive (%d/%d) from nfs server %s\n",
    559  1.1.1.2  fvdl 				 sizeof(u_long) - auio.uio_resid,
    560  1.1.1.2  fvdl 				 sizeof(u_long),
    561      1.1   cgd 				 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    562      1.1   cgd 			    error = EPIPE;
    563      1.1   cgd 			}
    564      1.1   cgd 			if (error)
    565      1.1   cgd 				goto errout;
    566      1.1   cgd 			len = ntohl(len) & ~0x80000000;
    567      1.1   cgd 			/*
    568      1.1   cgd 			 * This is SERIOUS! We are out of sync with the sender
    569      1.1   cgd 			 * and forcing a disconnect/reconnect is all I can do.
    570      1.1   cgd 			 */
    571      1.1   cgd 			if (len > NFS_MAXPACKET) {
    572  1.1.1.2  fvdl 			    log(LOG_ERR, "%s (%d) from nfs server %s\n",
    573  1.1.1.2  fvdl 				"impossible packet length",
    574  1.1.1.2  fvdl 				len,
    575  1.1.1.2  fvdl 				rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    576      1.1   cgd 			    error = EFBIG;
    577      1.1   cgd 			    goto errout;
    578      1.1   cgd 			}
    579      1.1   cgd 			auio.uio_resid = len;
    580      1.1   cgd 			do {
    581      1.1   cgd 			    rcvflg = MSG_WAITALL;
    582      1.1   cgd 			    error =  soreceive(so, (struct mbuf **)0,
    583      1.1   cgd 				&auio, mp, (struct mbuf **)0, &rcvflg);
    584      1.1   cgd 			} while (error == EWOULDBLOCK || error == EINTR ||
    585      1.1   cgd 				 error == ERESTART);
    586      1.1   cgd 			if (!error && auio.uio_resid > 0) {
    587  1.1.1.2  fvdl 			    log(LOG_INFO,
    588  1.1.1.2  fvdl 				"short receive (%d/%d) from nfs server %s\n",
    589  1.1.1.2  fvdl 				len - auio.uio_resid, len,
    590  1.1.1.2  fvdl 				rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    591      1.1   cgd 			    error = EPIPE;
    592      1.1   cgd 			}
    593      1.1   cgd 		} else {
    594  1.1.1.2  fvdl 			/*
    595  1.1.1.2  fvdl 			 * NB: Since uio_resid is big, MSG_WAITALL is ignored
    596  1.1.1.2  fvdl 			 * and soreceive() will return when it has either a
    597  1.1.1.2  fvdl 			 * control msg or a data msg.
    598  1.1.1.2  fvdl 			 * We have no use for control msg., but must grab them
    599  1.1.1.2  fvdl 			 * and then throw them away so we know what is going
    600  1.1.1.2  fvdl 			 * on.
    601  1.1.1.2  fvdl 			 */
    602  1.1.1.2  fvdl 			auio.uio_resid = len = 100000000; /* Anything Big */
    603  1.1.1.2  fvdl 			auio.uio_procp = p;
    604      1.1   cgd 			do {
    605      1.1   cgd 			    rcvflg = 0;
    606      1.1   cgd 			    error =  soreceive(so, (struct mbuf **)0,
    607  1.1.1.2  fvdl 				&auio, mp, &control, &rcvflg);
    608  1.1.1.2  fvdl 			    if (control)
    609  1.1.1.2  fvdl 				m_freem(control);
    610      1.1   cgd 			    if (error == EWOULDBLOCK && rep) {
    611      1.1   cgd 				if (rep->r_flags & R_SOFTTERM)
    612      1.1   cgd 					return (EINTR);
    613      1.1   cgd 			    }
    614  1.1.1.2  fvdl 			} while (error == EWOULDBLOCK ||
    615  1.1.1.2  fvdl 				 (!error && *mp == NULL && control));
    616  1.1.1.2  fvdl 			if ((rcvflg & MSG_EOR) == 0)
    617  1.1.1.2  fvdl 				printf("Egad!!\n");
    618      1.1   cgd 			if (!error && *mp == NULL)
    619      1.1   cgd 				error = EPIPE;
    620      1.1   cgd 			len -= auio.uio_resid;
    621      1.1   cgd 		}
    622      1.1   cgd errout:
    623  1.1.1.2  fvdl 		if (error && error != EINTR && error != ERESTART) {
    624      1.1   cgd 			m_freem(*mp);
    625      1.1   cgd 			*mp = (struct mbuf *)0;
    626  1.1.1.2  fvdl 			if (error != EPIPE)
    627      1.1   cgd 				log(LOG_INFO,
    628      1.1   cgd 				    "receive error %d from nfs server %s\n",
    629      1.1   cgd 				    error,
    630      1.1   cgd 				 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    631  1.1.1.2  fvdl 			error = nfs_sndlock(&rep->r_nmp->nm_flag, rep);
    632  1.1.1.2  fvdl 			if (!error)
    633  1.1.1.2  fvdl 				error = nfs_reconnect(rep);
    634      1.1   cgd 			if (!error)
    635      1.1   cgd 				goto tryagain;
    636      1.1   cgd 		}
    637      1.1   cgd 	} else {
    638  1.1.1.2  fvdl 		if ((so = rep->r_nmp->nm_so) == NULL)
    639  1.1.1.2  fvdl 			return (EACCES);
    640      1.1   cgd 		if (so->so_state & SS_ISCONNECTED)
    641      1.1   cgd 			getnam = (struct mbuf **)0;
    642      1.1   cgd 		else
    643      1.1   cgd 			getnam = aname;
    644      1.1   cgd 		auio.uio_resid = len = 1000000;
    645  1.1.1.2  fvdl 		auio.uio_procp = p;
    646      1.1   cgd 		do {
    647      1.1   cgd 			rcvflg = 0;
    648      1.1   cgd 			error =  soreceive(so, getnam, &auio, mp,
    649      1.1   cgd 				(struct mbuf **)0, &rcvflg);
    650  1.1.1.2  fvdl 			if (error == EWOULDBLOCK &&
    651      1.1   cgd 			    (rep->r_flags & R_SOFTTERM))
    652      1.1   cgd 				return (EINTR);
    653      1.1   cgd 		} while (error == EWOULDBLOCK);
    654      1.1   cgd 		len -= auio.uio_resid;
    655      1.1   cgd 	}
    656      1.1   cgd 	if (error) {
    657      1.1   cgd 		m_freem(*mp);
    658      1.1   cgd 		*mp = (struct mbuf *)0;
    659      1.1   cgd 	}
    660      1.1   cgd 	/*
    661  1.1.1.2  fvdl 	 * Search for any mbufs that are not a multiple of 4 bytes long
    662  1.1.1.2  fvdl 	 * or with m_data not longword aligned.
    663      1.1   cgd 	 * These could cause pointer alignment problems, so copy them to
    664      1.1   cgd 	 * well aligned mbufs.
    665      1.1   cgd 	 */
    666  1.1.1.2  fvdl 	nfs_realign(*mp, 5 * NFSX_UNSIGNED);
    667      1.1   cgd 	return (error);
    668      1.1   cgd }
    669      1.1   cgd 
    670      1.1   cgd /*
    671      1.1   cgd  * Implement receipt of reply on a socket.
    672      1.1   cgd  * We must search through the list of received datagrams matching them
    673      1.1   cgd  * with outstanding requests using the xid, until ours is found.
    674      1.1   cgd  */
    675      1.1   cgd /* ARGSUSED */
    676  1.1.1.2  fvdl int
    677  1.1.1.2  fvdl nfs_reply(myrep)
    678      1.1   cgd 	struct nfsreq *myrep;
    679      1.1   cgd {
    680      1.1   cgd 	register struct nfsreq *rep;
    681  1.1.1.2  fvdl 	register struct nfsmount *nmp = myrep->r_nmp;
    682  1.1.1.2  fvdl 	register long t1;
    683  1.1.1.2  fvdl 	struct mbuf *mrep, *nam, *md;
    684  1.1.1.2  fvdl 	u_long rxid, *tl;
    685  1.1.1.2  fvdl 	caddr_t dpos, cp2;
    686  1.1.1.2  fvdl 	int error;
    687      1.1   cgd 
    688      1.1   cgd 	/*
    689      1.1   cgd 	 * Loop around until we get our own reply
    690      1.1   cgd 	 */
    691      1.1   cgd 	for (;;) {
    692      1.1   cgd 		/*
    693      1.1   cgd 		 * Lock against other receivers so that I don't get stuck in
    694      1.1   cgd 		 * sbwait() after someone else has received my reply for me.
    695      1.1   cgd 		 * Also necessary for connection based protocols to avoid
    696      1.1   cgd 		 * race conditions during a reconnect.
    697      1.1   cgd 		 */
    698  1.1.1.2  fvdl 		error = nfs_rcvlock(myrep);
    699  1.1.1.2  fvdl 		if (error)
    700  1.1.1.2  fvdl 			return (error);
    701      1.1   cgd 		/* Already received, bye bye */
    702      1.1   cgd 		if (myrep->r_mrep != NULL) {
    703  1.1.1.2  fvdl 			nfs_rcvunlock(&nmp->nm_flag);
    704      1.1   cgd 			return (0);
    705      1.1   cgd 		}
    706      1.1   cgd 		/*
    707      1.1   cgd 		 * Get the next Rpc reply off the socket
    708      1.1   cgd 		 */
    709  1.1.1.2  fvdl 		error = nfs_receive(myrep, &nam, &mrep);
    710  1.1.1.2  fvdl 		nfs_rcvunlock(&nmp->nm_flag);
    711  1.1.1.2  fvdl 		if (error) {
    712      1.1   cgd 
    713      1.1   cgd 			/*
    714      1.1   cgd 			 * Ignore routing errors on connectionless protocols??
    715      1.1   cgd 			 */
    716      1.1   cgd 			if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
    717      1.1   cgd 				nmp->nm_so->so_error = 0;
    718  1.1.1.2  fvdl 				if (myrep->r_flags & R_GETONEREP)
    719  1.1.1.2  fvdl 					return (0);
    720      1.1   cgd 				continue;
    721      1.1   cgd 			}
    722      1.1   cgd 			return (error);
    723      1.1   cgd 		}
    724  1.1.1.2  fvdl 		if (nam)
    725  1.1.1.2  fvdl 			m_freem(nam);
    726      1.1   cgd 
    727      1.1   cgd 		/*
    728      1.1   cgd 		 * Get the xid and check that it is an rpc reply
    729      1.1   cgd 		 */
    730  1.1.1.2  fvdl 		md = mrep;
    731  1.1.1.2  fvdl 		dpos = mtod(md, caddr_t);
    732  1.1.1.2  fvdl 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
    733  1.1.1.2  fvdl 		rxid = *tl++;
    734  1.1.1.2  fvdl 		if (*tl != rpc_reply) {
    735  1.1.1.2  fvdl 			if (nmp->nm_flag & NFSMNT_NQNFS) {
    736  1.1.1.2  fvdl 				if (nqnfs_callback(nmp, mrep, md, dpos))
    737  1.1.1.2  fvdl 					nfsstats.rpcinvalid++;
    738  1.1.1.2  fvdl 			} else {
    739  1.1.1.2  fvdl 				nfsstats.rpcinvalid++;
    740  1.1.1.2  fvdl 				m_freem(mrep);
    741  1.1.1.2  fvdl 			}
    742  1.1.1.2  fvdl nfsmout:
    743  1.1.1.2  fvdl 			if (myrep->r_flags & R_GETONEREP)
    744  1.1.1.2  fvdl 				return (0);
    745      1.1   cgd 			continue;
    746      1.1   cgd 		}
    747  1.1.1.2  fvdl 
    748      1.1   cgd 		/*
    749      1.1   cgd 		 * Loop through the request list to match up the reply
    750      1.1   cgd 		 * Iff no match, just drop the datagram
    751      1.1   cgd 		 */
    752  1.1.1.2  fvdl 		for (rep = nfs_reqq.tqh_first; rep != 0;
    753  1.1.1.2  fvdl 		    rep = rep->r_chain.tqe_next) {
    754      1.1   cgd 			if (rep->r_mrep == NULL && rxid == rep->r_xid) {
    755      1.1   cgd 				/* Found it.. */
    756  1.1.1.2  fvdl 				rep->r_mrep = mrep;
    757  1.1.1.2  fvdl 				rep->r_md = md;
    758  1.1.1.2  fvdl 				rep->r_dpos = dpos;
    759  1.1.1.2  fvdl 				if (nfsrtton) {
    760  1.1.1.2  fvdl 					struct rttl *rt;
    761  1.1.1.2  fvdl 
    762  1.1.1.2  fvdl 					rt = &nfsrtt.rttl[nfsrtt.pos];
    763  1.1.1.2  fvdl 					rt->proc = rep->r_procnum;
    764  1.1.1.2  fvdl 					rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]);
    765  1.1.1.2  fvdl 					rt->sent = nmp->nm_sent;
    766  1.1.1.2  fvdl 					rt->cwnd = nmp->nm_cwnd;
    767  1.1.1.2  fvdl 					rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1];
    768  1.1.1.2  fvdl 					rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1];
    769  1.1.1.2  fvdl 					rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid;
    770  1.1.1.2  fvdl 					rt->tstamp = time;
    771  1.1.1.2  fvdl 					if (rep->r_flags & R_TIMING)
    772  1.1.1.2  fvdl 						rt->rtt = rep->r_rtt;
    773  1.1.1.2  fvdl 					else
    774  1.1.1.2  fvdl 						rt->rtt = 1000000;
    775  1.1.1.2  fvdl 					nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ;
    776  1.1.1.2  fvdl 				}
    777      1.1   cgd 				/*
    778  1.1.1.2  fvdl 				 * Update congestion window.
    779  1.1.1.2  fvdl 				 * Do the additive increase of
    780  1.1.1.2  fvdl 				 * one rpc/rtt.
    781      1.1   cgd 				 */
    782  1.1.1.2  fvdl 				if (nmp->nm_cwnd <= nmp->nm_sent) {
    783  1.1.1.2  fvdl 					nmp->nm_cwnd +=
    784  1.1.1.2  fvdl 					   (NFS_CWNDSCALE * NFS_CWNDSCALE +
    785  1.1.1.2  fvdl 					   (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd;
    786  1.1.1.2  fvdl 					if (nmp->nm_cwnd > NFS_MAXCWND)
    787  1.1.1.2  fvdl 						nmp->nm_cwnd = NFS_MAXCWND;
    788      1.1   cgd 				}
    789  1.1.1.2  fvdl 				rep->r_flags &= ~R_SENT;
    790  1.1.1.2  fvdl 				nmp->nm_sent -= NFS_CWNDSCALE;
    791  1.1.1.2  fvdl 				/*
    792  1.1.1.2  fvdl 				 * Update rtt using a gain of 0.125 on the mean
    793  1.1.1.2  fvdl 				 * and a gain of 0.25 on the deviation.
    794  1.1.1.2  fvdl 				 */
    795  1.1.1.2  fvdl 				if (rep->r_flags & R_TIMING) {
    796  1.1.1.2  fvdl 					/*
    797  1.1.1.2  fvdl 					 * Since the timer resolution of
    798  1.1.1.2  fvdl 					 * NFS_HZ is so course, it can often
    799  1.1.1.2  fvdl 					 * result in r_rtt == 0. Since
    800  1.1.1.2  fvdl 					 * r_rtt == N means that the actual
    801  1.1.1.2  fvdl 					 * rtt is between N+dt and N+2-dt ticks,
    802  1.1.1.2  fvdl 					 * add 1.
    803  1.1.1.2  fvdl 					 */
    804  1.1.1.2  fvdl 					t1 = rep->r_rtt + 1;
    805  1.1.1.2  fvdl 					t1 -= (NFS_SRTT(rep) >> 3);
    806  1.1.1.2  fvdl 					NFS_SRTT(rep) += t1;
    807  1.1.1.2  fvdl 					if (t1 < 0)
    808  1.1.1.2  fvdl 						t1 = -t1;
    809  1.1.1.2  fvdl 					t1 -= (NFS_SDRTT(rep) >> 2);
    810  1.1.1.2  fvdl 					NFS_SDRTT(rep) += t1;
    811      1.1   cgd 				}
    812  1.1.1.2  fvdl 				nmp->nm_timeouts = 0;
    813      1.1   cgd 				break;
    814      1.1   cgd 			}
    815      1.1   cgd 		}
    816      1.1   cgd 		/*
    817      1.1   cgd 		 * If not matched to a request, drop it.
    818      1.1   cgd 		 * If it's mine, get out.
    819      1.1   cgd 		 */
    820  1.1.1.2  fvdl 		if (rep == 0) {
    821      1.1   cgd 			nfsstats.rpcunexpected++;
    822  1.1.1.2  fvdl 			m_freem(mrep);
    823  1.1.1.2  fvdl 		} else if (rep == myrep) {
    824  1.1.1.2  fvdl 			if (rep->r_mrep == NULL)
    825  1.1.1.2  fvdl 				panic("nfsreply nil");
    826  1.1.1.2  fvdl 			return (0);
    827  1.1.1.2  fvdl 		}
    828  1.1.1.2  fvdl 		if (myrep->r_flags & R_GETONEREP)
    829      1.1   cgd 			return (0);
    830      1.1   cgd 	}
    831      1.1   cgd }
    832      1.1   cgd 
    833      1.1   cgd /*
    834      1.1   cgd  * nfs_request - goes something like this
    835      1.1   cgd  *	- fill in request struct
    836      1.1   cgd  *	- links it into list
    837      1.1   cgd  *	- calls nfs_send() for first transmit
    838      1.1   cgd  *	- calls nfs_receive() to get reply
    839      1.1   cgd  *	- break down rpc header and return with nfs reply pointed to
    840      1.1   cgd  *	  by mrep or error
    841      1.1   cgd  * nb: always frees up mreq mbuf list
    842      1.1   cgd  */
    843  1.1.1.2  fvdl int
    844  1.1.1.2  fvdl nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp)
    845      1.1   cgd 	struct vnode *vp;
    846  1.1.1.2  fvdl 	struct mbuf *mrest;
    847      1.1   cgd 	int procnum;
    848      1.1   cgd 	struct proc *procp;
    849  1.1.1.2  fvdl 	struct ucred *cred;
    850      1.1   cgd 	struct mbuf **mrp;
    851      1.1   cgd 	struct mbuf **mdp;
    852      1.1   cgd 	caddr_t *dposp;
    853      1.1   cgd {
    854      1.1   cgd 	register struct mbuf *m, *mrep;
    855      1.1   cgd 	register struct nfsreq *rep;
    856      1.1   cgd 	register u_long *tl;
    857  1.1.1.2  fvdl 	register int i;
    858      1.1   cgd 	struct nfsmount *nmp;
    859  1.1.1.2  fvdl 	struct mbuf *md, *mheadend;
    860  1.1.1.2  fvdl 	struct nfsnode *np;
    861  1.1.1.2  fvdl 	char nickv[RPCX_NICKVERF];
    862  1.1.1.2  fvdl 	time_t reqtime, waituntil;
    863  1.1.1.2  fvdl 	caddr_t dpos, cp2;
    864  1.1.1.2  fvdl 	int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type;
    865  1.1.1.2  fvdl 	int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0;
    866  1.1.1.2  fvdl 	int verf_len, verf_type;
    867  1.1.1.2  fvdl 	u_long xid;
    868  1.1.1.2  fvdl 	u_quad_t frev;
    869  1.1.1.2  fvdl 	char *auth_str, *verf_str;
    870  1.1.1.2  fvdl 	NFSKERBKEY_T key;		/* save session key */
    871      1.1   cgd 
    872  1.1.1.2  fvdl 	nmp = VFSTONFS(vp->v_mount);
    873      1.1   cgd 	MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
    874      1.1   cgd 	rep->r_nmp = nmp;
    875      1.1   cgd 	rep->r_vp = vp;
    876      1.1   cgd 	rep->r_procp = procp;
    877  1.1.1.2  fvdl 	rep->r_procnum = procnum;
    878  1.1.1.2  fvdl 	i = 0;
    879  1.1.1.2  fvdl 	m = mrest;
    880      1.1   cgd 	while (m) {
    881  1.1.1.2  fvdl 		i += m->m_len;
    882      1.1   cgd 		m = m->m_next;
    883      1.1   cgd 	}
    884  1.1.1.2  fvdl 	mrest_len = i;
    885  1.1.1.2  fvdl 
    886  1.1.1.2  fvdl 	/*
    887  1.1.1.2  fvdl 	 * Get the RPC header with authorization.
    888  1.1.1.2  fvdl 	 */
    889  1.1.1.2  fvdl kerbauth:
    890  1.1.1.2  fvdl 	verf_str = auth_str = (char *)0;
    891  1.1.1.2  fvdl 	if (nmp->nm_flag & NFSMNT_KERB) {
    892  1.1.1.2  fvdl 		verf_str = nickv;
    893  1.1.1.2  fvdl 		verf_len = sizeof (nickv);
    894  1.1.1.2  fvdl 		auth_type = RPCAUTH_KERB4;
    895  1.1.1.2  fvdl 		bzero((caddr_t)key, sizeof (key));
    896  1.1.1.2  fvdl 		if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str,
    897  1.1.1.2  fvdl 			&auth_len, verf_str, verf_len)) {
    898  1.1.1.2  fvdl 			error = nfs_getauth(nmp, rep, cred, &auth_str,
    899  1.1.1.2  fvdl 				&auth_len, verf_str, &verf_len, key);
    900  1.1.1.2  fvdl 			if (error) {
    901  1.1.1.2  fvdl 				free((caddr_t)rep, M_NFSREQ);
    902  1.1.1.2  fvdl 				m_freem(mrest);
    903  1.1.1.2  fvdl 				return (error);
    904  1.1.1.2  fvdl 			}
    905      1.1   cgd 		}
    906  1.1.1.2  fvdl 	} else {
    907  1.1.1.2  fvdl 		auth_type = RPCAUTH_UNIX;
    908  1.1.1.2  fvdl 		if (cred->cr_ngroups < 1)
    909  1.1.1.2  fvdl 			panic("nfsreq nogrps");
    910  1.1.1.2  fvdl 		auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ?
    911  1.1.1.2  fvdl 			nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) +
    912  1.1.1.2  fvdl 			5 * NFSX_UNSIGNED;
    913  1.1.1.2  fvdl 	}
    914  1.1.1.2  fvdl 	m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len,
    915  1.1.1.2  fvdl 	     auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid);
    916  1.1.1.2  fvdl 	if (auth_str)
    917  1.1.1.2  fvdl 		free(auth_str, M_TEMP);
    918  1.1.1.2  fvdl 
    919      1.1   cgd 	/*
    920  1.1.1.2  fvdl 	 * For stream protocols, insert a Sun RPC Record Mark.
    921      1.1   cgd 	 */
    922  1.1.1.2  fvdl 	if (nmp->nm_sotype == SOCK_STREAM) {
    923  1.1.1.2  fvdl 		M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
    924  1.1.1.2  fvdl 		*mtod(m, u_long *) = htonl(0x80000000 |
    925  1.1.1.2  fvdl 			 (m->m_pkthdr.len - NFSX_UNSIGNED));
    926      1.1   cgd 	}
    927  1.1.1.2  fvdl 	rep->r_mreq = m;
    928  1.1.1.2  fvdl 	rep->r_xid = xid;
    929  1.1.1.2  fvdl tryagain:
    930  1.1.1.2  fvdl 	if (nmp->nm_flag & NFSMNT_SOFT)
    931  1.1.1.2  fvdl 		rep->r_retry = nmp->nm_retry;
    932  1.1.1.2  fvdl 	else
    933  1.1.1.2  fvdl 		rep->r_retry = NFS_MAXREXMIT + 1;	/* past clip limit */
    934  1.1.1.2  fvdl 	rep->r_rtt = rep->r_rexmit = 0;
    935  1.1.1.2  fvdl 	if (proct[procnum] > 0)
    936  1.1.1.2  fvdl 		rep->r_flags = R_TIMING;
    937  1.1.1.2  fvdl 	else
    938  1.1.1.2  fvdl 		rep->r_flags = 0;
    939  1.1.1.2  fvdl 	rep->r_mrep = NULL;
    940      1.1   cgd 
    941      1.1   cgd 	/*
    942      1.1   cgd 	 * Do the client side RPC.
    943      1.1   cgd 	 */
    944      1.1   cgd 	nfsstats.rpcrequests++;
    945      1.1   cgd 	/*
    946      1.1   cgd 	 * Chain request into list of outstanding requests. Be sure
    947      1.1   cgd 	 * to put it LAST so timer finds oldest requests first.
    948      1.1   cgd 	 */
    949  1.1.1.2  fvdl 	s = splsoftclock();
    950  1.1.1.2  fvdl 	TAILQ_INSERT_TAIL(&nfs_reqq, rep, r_chain);
    951  1.1.1.2  fvdl 
    952  1.1.1.2  fvdl 	/* Get send time for nqnfs */
    953  1.1.1.2  fvdl 	reqtime = time.tv_sec;
    954  1.1.1.2  fvdl 
    955      1.1   cgd 	/*
    956      1.1   cgd 	 * If backing off another request or avoiding congestion, don't
    957      1.1   cgd 	 * send this one now but let timer do it. If not timing a request,
    958      1.1   cgd 	 * do it now.
    959      1.1   cgd 	 */
    960  1.1.1.2  fvdl 	if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM ||
    961  1.1.1.2  fvdl 		(nmp->nm_flag & NFSMNT_DUMBTIMR) ||
    962  1.1.1.2  fvdl 		nmp->nm_sent < nmp->nm_cwnd)) {
    963      1.1   cgd 		splx(s);
    964      1.1   cgd 		if (nmp->nm_soflags & PR_CONNREQUIRED)
    965  1.1.1.2  fvdl 			error = nfs_sndlock(&nmp->nm_flag, rep);
    966  1.1.1.2  fvdl 		if (!error) {
    967  1.1.1.2  fvdl 			m = m_copym(m, 0, M_COPYALL, M_WAIT);
    968  1.1.1.2  fvdl 			error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);
    969  1.1.1.2  fvdl 			if (nmp->nm_soflags & PR_CONNREQUIRED)
    970  1.1.1.2  fvdl 				nfs_sndunlock(&nmp->nm_flag);
    971  1.1.1.2  fvdl 		}
    972  1.1.1.2  fvdl 		if (!error && (rep->r_flags & R_MUSTRESEND) == 0) {
    973  1.1.1.2  fvdl 			nmp->nm_sent += NFS_CWNDSCALE;
    974  1.1.1.2  fvdl 			rep->r_flags |= R_SENT;
    975  1.1.1.2  fvdl 		}
    976  1.1.1.2  fvdl 	} else {
    977      1.1   cgd 		splx(s);
    978  1.1.1.2  fvdl 		rep->r_rtt = -1;
    979  1.1.1.2  fvdl 	}
    980      1.1   cgd 
    981      1.1   cgd 	/*
    982      1.1   cgd 	 * Wait for the reply from our send or the timer's.
    983      1.1   cgd 	 */
    984  1.1.1.2  fvdl 	if (!error || error == EPIPE)
    985  1.1.1.2  fvdl 		error = nfs_reply(rep);
    986      1.1   cgd 
    987      1.1   cgd 	/*
    988      1.1   cgd 	 * RPC done, unlink the request.
    989      1.1   cgd 	 */
    990  1.1.1.2  fvdl 	s = splsoftclock();
    991  1.1.1.2  fvdl 	TAILQ_REMOVE(&nfs_reqq, rep, r_chain);
    992      1.1   cgd 	splx(s);
    993      1.1   cgd 
    994      1.1   cgd 	/*
    995  1.1.1.2  fvdl 	 * Decrement the outstanding request count.
    996  1.1.1.2  fvdl 	 */
    997  1.1.1.2  fvdl 	if (rep->r_flags & R_SENT) {
    998  1.1.1.2  fvdl 		rep->r_flags &= ~R_SENT;	/* paranoia */
    999  1.1.1.2  fvdl 		nmp->nm_sent -= NFS_CWNDSCALE;
   1000  1.1.1.2  fvdl 	}
   1001  1.1.1.2  fvdl 
   1002  1.1.1.2  fvdl 	/*
   1003      1.1   cgd 	 * If there was a successful reply and a tprintf msg.
   1004      1.1   cgd 	 * tprintf a response.
   1005      1.1   cgd 	 */
   1006      1.1   cgd 	if (!error && (rep->r_flags & R_TPRINTFMSG))
   1007      1.1   cgd 		nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
   1008      1.1   cgd 		    "is alive again");
   1009      1.1   cgd 	mrep = rep->r_mrep;
   1010  1.1.1.2  fvdl 	md = rep->r_md;
   1011  1.1.1.2  fvdl 	dpos = rep->r_dpos;
   1012  1.1.1.2  fvdl 	if (error) {
   1013  1.1.1.2  fvdl 		m_freem(rep->r_mreq);
   1014  1.1.1.2  fvdl 		free((caddr_t)rep, M_NFSREQ);
   1015      1.1   cgd 		return (error);
   1016  1.1.1.2  fvdl 	}
   1017      1.1   cgd 
   1018      1.1   cgd 	/*
   1019      1.1   cgd 	 * break down the rpc header and check if ok
   1020      1.1   cgd 	 */
   1021  1.1.1.2  fvdl 	nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
   1022      1.1   cgd 	if (*tl++ == rpc_msgdenied) {
   1023      1.1   cgd 		if (*tl == rpc_mismatch)
   1024      1.1   cgd 			error = EOPNOTSUPP;
   1025  1.1.1.2  fvdl 		else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) {
   1026  1.1.1.2  fvdl 			if (!failed_auth) {
   1027  1.1.1.2  fvdl 				failed_auth++;
   1028  1.1.1.2  fvdl 				mheadend->m_next = (struct mbuf *)0;
   1029  1.1.1.2  fvdl 				m_freem(mrep);
   1030  1.1.1.2  fvdl 				m_freem(rep->r_mreq);
   1031  1.1.1.2  fvdl 				goto kerbauth;
   1032  1.1.1.2  fvdl 			} else
   1033  1.1.1.2  fvdl 				error = EAUTH;
   1034  1.1.1.2  fvdl 		} else
   1035      1.1   cgd 			error = EACCES;
   1036      1.1   cgd 		m_freem(mrep);
   1037  1.1.1.2  fvdl 		m_freem(rep->r_mreq);
   1038  1.1.1.2  fvdl 		free((caddr_t)rep, M_NFSREQ);
   1039      1.1   cgd 		return (error);
   1040      1.1   cgd 	}
   1041  1.1.1.2  fvdl 
   1042      1.1   cgd 	/*
   1043  1.1.1.2  fvdl 	 * Grab any Kerberos verifier, otherwise just throw it away.
   1044      1.1   cgd 	 */
   1045  1.1.1.2  fvdl 	verf_type = fxdr_unsigned(int, *tl++);
   1046  1.1.1.2  fvdl 	i = fxdr_unsigned(int, *tl);
   1047  1.1.1.2  fvdl 	if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) {
   1048  1.1.1.2  fvdl 		error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep);
   1049  1.1.1.2  fvdl 		if (error)
   1050  1.1.1.2  fvdl 			goto nfsmout;
   1051  1.1.1.2  fvdl 	} else if (i > 0)
   1052  1.1.1.2  fvdl 		nfsm_adv(nfsm_rndup(i));
   1053  1.1.1.2  fvdl 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
   1054      1.1   cgd 	/* 0 == ok */
   1055      1.1   cgd 	if (*tl == 0) {
   1056  1.1.1.2  fvdl 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
   1057      1.1   cgd 		if (*tl != 0) {
   1058      1.1   cgd 			error = fxdr_unsigned(int, *tl);
   1059  1.1.1.2  fvdl 			if ((nmp->nm_flag & NFSMNT_NFSV3) &&
   1060  1.1.1.2  fvdl 				error == NFSERR_TRYLATER) {
   1061  1.1.1.2  fvdl 				m_freem(mrep);
   1062  1.1.1.2  fvdl 				error = 0;
   1063  1.1.1.2  fvdl 				waituntil = time.tv_sec + trylater_delay;
   1064  1.1.1.2  fvdl 				while (time.tv_sec < waituntil)
   1065  1.1.1.2  fvdl 					(void) tsleep((caddr_t)&lbolt,
   1066  1.1.1.2  fvdl 						PSOCK, "nqnfstry", 0);
   1067  1.1.1.2  fvdl 				trylater_delay *= nfs_backoff[trylater_cnt];
   1068  1.1.1.2  fvdl 				if (trylater_cnt < 7)
   1069  1.1.1.2  fvdl 					trylater_cnt++;
   1070  1.1.1.2  fvdl 				goto tryagain;
   1071  1.1.1.2  fvdl 			}
   1072  1.1.1.2  fvdl 
   1073  1.1.1.2  fvdl 			/*
   1074  1.1.1.2  fvdl 			 * If the File Handle was stale, invalidate the
   1075  1.1.1.2  fvdl 			 * lookup cache, just in case.
   1076  1.1.1.2  fvdl 			 */
   1077  1.1.1.2  fvdl 			if (error == ESTALE)
   1078  1.1.1.2  fvdl 				cache_purge(vp);
   1079  1.1.1.2  fvdl 			if (nmp->nm_flag & NFSMNT_NFSV3) {
   1080  1.1.1.2  fvdl 				*mrp = mrep;
   1081  1.1.1.2  fvdl 				*mdp = md;
   1082  1.1.1.2  fvdl 				*dposp = dpos;
   1083  1.1.1.2  fvdl 				error |= NFSERR_RETERR;
   1084  1.1.1.2  fvdl 			} else
   1085  1.1.1.2  fvdl 				m_freem(mrep);
   1086  1.1.1.2  fvdl 			m_freem(rep->r_mreq);
   1087  1.1.1.2  fvdl 			free((caddr_t)rep, M_NFSREQ);
   1088      1.1   cgd 			return (error);
   1089      1.1   cgd 		}
   1090  1.1.1.2  fvdl 
   1091  1.1.1.2  fvdl 		/*
   1092  1.1.1.2  fvdl 		 * For nqnfs, get any lease in reply
   1093  1.1.1.2  fvdl 		 */
   1094  1.1.1.2  fvdl 		if (nmp->nm_flag & NFSMNT_NQNFS) {
   1095  1.1.1.2  fvdl 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
   1096  1.1.1.2  fvdl 			if (*tl) {
   1097  1.1.1.2  fvdl 				np = VTONFS(vp);
   1098  1.1.1.2  fvdl 				nqlflag = fxdr_unsigned(int, *tl);
   1099  1.1.1.2  fvdl 				nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
   1100  1.1.1.2  fvdl 				cachable = fxdr_unsigned(int, *tl++);
   1101  1.1.1.2  fvdl 				reqtime += fxdr_unsigned(int, *tl++);
   1102  1.1.1.2  fvdl 				if (reqtime > time.tv_sec) {
   1103  1.1.1.2  fvdl 				    fxdr_hyper(tl, &frev);
   1104  1.1.1.2  fvdl 				    nqnfs_clientlease(nmp, np, nqlflag,
   1105  1.1.1.2  fvdl 					cachable, reqtime, frev);
   1106  1.1.1.2  fvdl 				}
   1107  1.1.1.2  fvdl 			}
   1108  1.1.1.2  fvdl 		}
   1109      1.1   cgd 		*mrp = mrep;
   1110      1.1   cgd 		*mdp = md;
   1111      1.1   cgd 		*dposp = dpos;
   1112  1.1.1.2  fvdl 		m_freem(rep->r_mreq);
   1113  1.1.1.2  fvdl 		FREE((caddr_t)rep, M_NFSREQ);
   1114      1.1   cgd 		return (0);
   1115      1.1   cgd 	}
   1116      1.1   cgd 	m_freem(mrep);
   1117  1.1.1.2  fvdl 	error = EPROTONOSUPPORT;
   1118      1.1   cgd nfsmout:
   1119  1.1.1.2  fvdl 	m_freem(rep->r_mreq);
   1120  1.1.1.2  fvdl 	free((caddr_t)rep, M_NFSREQ);
   1121      1.1   cgd 	return (error);
   1122      1.1   cgd }
   1123      1.1   cgd 
   1124      1.1   cgd /*
   1125  1.1.1.2  fvdl  * Generate the rpc reply header
   1126  1.1.1.2  fvdl  * siz arg. is used to decide if adding a cluster is worthwhile
   1127      1.1   cgd  */
   1128  1.1.1.2  fvdl int
   1129  1.1.1.2  fvdl nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp)
   1130  1.1.1.2  fvdl 	int siz;
   1131  1.1.1.2  fvdl 	struct nfsrv_descript *nd;
   1132  1.1.1.2  fvdl 	struct nfssvc_sock *slp;
   1133  1.1.1.2  fvdl 	int err;
   1134  1.1.1.2  fvdl 	int cache;
   1135  1.1.1.2  fvdl 	u_quad_t *frev;
   1136  1.1.1.2  fvdl 	struct mbuf **mrq;
   1137  1.1.1.2  fvdl 	struct mbuf **mbp;
   1138  1.1.1.2  fvdl 	caddr_t *bposp;
   1139      1.1   cgd {
   1140      1.1   cgd 	register u_long *tl;
   1141  1.1.1.2  fvdl 	register struct mbuf *mreq;
   1142  1.1.1.2  fvdl 	caddr_t bpos;
   1143  1.1.1.2  fvdl 	struct mbuf *mb, *mb2;
   1144      1.1   cgd 
   1145  1.1.1.2  fvdl 	MGETHDR(mreq, M_WAIT, MT_DATA);
   1146  1.1.1.2  fvdl 	mb = mreq;
   1147  1.1.1.2  fvdl 	/*
   1148  1.1.1.2  fvdl 	 * If this is a big reply, use a cluster else
   1149  1.1.1.2  fvdl 	 * try and leave leading space for the lower level headers.
   1150  1.1.1.2  fvdl 	 */
   1151  1.1.1.2  fvdl 	siz += RPC_REPLYSIZ;
   1152  1.1.1.2  fvdl 	if (siz >= MINCLSIZE) {
   1153  1.1.1.2  fvdl 		MCLGET(mreq, M_WAIT);
   1154  1.1.1.2  fvdl 	} else
   1155  1.1.1.2  fvdl 		mreq->m_data += max_hdr;
   1156  1.1.1.2  fvdl 	tl = mtod(mreq, u_long *);
   1157  1.1.1.2  fvdl 	mreq->m_len = 6 * NFSX_UNSIGNED;
   1158  1.1.1.2  fvdl 	bpos = ((caddr_t)tl) + mreq->m_len;
   1159  1.1.1.2  fvdl 	*tl++ = txdr_unsigned(nd->nd_retxid);
   1160  1.1.1.2  fvdl 	*tl++ = rpc_reply;
   1161  1.1.1.2  fvdl 	if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) {
   1162  1.1.1.2  fvdl 		*tl++ = rpc_msgdenied;
   1163  1.1.1.2  fvdl 		if (err & NFSERR_AUTHERR) {
   1164  1.1.1.2  fvdl 			*tl++ = rpc_autherr;
   1165  1.1.1.2  fvdl 			*tl = txdr_unsigned(err & ~NFSERR_AUTHERR);
   1166  1.1.1.2  fvdl 			mreq->m_len -= NFSX_UNSIGNED;
   1167  1.1.1.2  fvdl 			bpos -= NFSX_UNSIGNED;
   1168  1.1.1.2  fvdl 		} else {
   1169  1.1.1.2  fvdl 			*tl++ = rpc_mismatch;
   1170  1.1.1.2  fvdl 			*tl++ = txdr_unsigned(RPC_VER2);
   1171  1.1.1.2  fvdl 			*tl = txdr_unsigned(RPC_VER2);
   1172  1.1.1.2  fvdl 		}
   1173      1.1   cgd 	} else {
   1174  1.1.1.2  fvdl 		*tl++ = rpc_msgaccepted;
   1175  1.1.1.2  fvdl 
   1176  1.1.1.2  fvdl 		/*
   1177  1.1.1.2  fvdl 		 * For Kerberos authentication, we must send the nickname
   1178  1.1.1.2  fvdl 		 * verifier back, otherwise just RPCAUTH_NULL.
   1179  1.1.1.2  fvdl 		 */
   1180  1.1.1.2  fvdl 		if (nd->nd_flag & ND_KERBFULL) {
   1181  1.1.1.2  fvdl 		    register struct nfsuid *nuidp;
   1182  1.1.1.2  fvdl 		    struct timeval ktvin, ktvout;
   1183  1.1.1.2  fvdl 		    NFSKERBKEYSCHED_T keys;	/* stores key schedule */
   1184  1.1.1.2  fvdl 
   1185  1.1.1.2  fvdl 		    for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first;
   1186  1.1.1.2  fvdl 			nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
   1187  1.1.1.2  fvdl 			if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid &&
   1188  1.1.1.2  fvdl 			    (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp),
   1189  1.1.1.2  fvdl 			     &nuidp->nu_haddr, nd->nd_nam2)))
   1190  1.1.1.2  fvdl 			    break;
   1191  1.1.1.2  fvdl 		    }
   1192  1.1.1.2  fvdl 		    if (nuidp) {
   1193  1.1.1.2  fvdl 			ktvin.tv_sec =
   1194  1.1.1.2  fvdl 			    txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1);
   1195  1.1.1.2  fvdl 			ktvin.tv_usec =
   1196  1.1.1.2  fvdl 			    txdr_unsigned(nuidp->nu_timestamp.tv_usec);
   1197  1.1.1.2  fvdl 
   1198  1.1.1.2  fvdl 			/*
   1199  1.1.1.2  fvdl 			 * Encrypt the timestamp in ecb mode using the
   1200  1.1.1.2  fvdl 			 * session key.
   1201  1.1.1.2  fvdl 			 */
   1202  1.1.1.2  fvdl #ifdef NFSKERB
   1203  1.1.1.2  fvdl 			XXX
   1204  1.1.1.2  fvdl #endif
   1205  1.1.1.2  fvdl 
   1206  1.1.1.2  fvdl 			*tl++ = rpc_auth_kerb;
   1207  1.1.1.2  fvdl 			*tl++ = txdr_unsigned(3 * NFSX_UNSIGNED);
   1208  1.1.1.2  fvdl 			*tl = ktvout.tv_sec;
   1209  1.1.1.2  fvdl 			nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
   1210  1.1.1.2  fvdl 			*tl++ = ktvout.tv_usec;
   1211  1.1.1.2  fvdl 			*tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid);
   1212  1.1.1.2  fvdl 		    } else {
   1213  1.1.1.2  fvdl 			*tl++ = 0;
   1214  1.1.1.2  fvdl 			*tl++ = 0;
   1215  1.1.1.2  fvdl 		    }
   1216  1.1.1.2  fvdl 		} else {
   1217  1.1.1.2  fvdl 			*tl++ = 0;
   1218  1.1.1.2  fvdl 			*tl++ = 0;
   1219  1.1.1.2  fvdl 		}
   1220  1.1.1.2  fvdl 		switch (err) {
   1221  1.1.1.2  fvdl 		case EPROGUNAVAIL:
   1222  1.1.1.2  fvdl 			*tl = txdr_unsigned(RPC_PROGUNAVAIL);
   1223  1.1.1.2  fvdl 			break;
   1224  1.1.1.2  fvdl 		case EPROGMISMATCH:
   1225  1.1.1.2  fvdl 			*tl = txdr_unsigned(RPC_PROGMISMATCH);
   1226  1.1.1.2  fvdl 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
   1227  1.1.1.2  fvdl 			if (nd->nd_flag & ND_NQNFS) {
   1228  1.1.1.2  fvdl 				*tl++ = txdr_unsigned(3);
   1229  1.1.1.2  fvdl 				*tl = txdr_unsigned(3);
   1230  1.1.1.2  fvdl 			} else {
   1231  1.1.1.2  fvdl 				*tl++ = txdr_unsigned(2);
   1232  1.1.1.2  fvdl 				*tl = txdr_unsigned(3);
   1233      1.1   cgd 			}
   1234      1.1   cgd 			break;
   1235      1.1   cgd 		case EPROCUNAVAIL:
   1236      1.1   cgd 			*tl = txdr_unsigned(RPC_PROCUNAVAIL);
   1237      1.1   cgd 			break;
   1238  1.1.1.2  fvdl 		case EBADRPC:
   1239  1.1.1.2  fvdl 			*tl = txdr_unsigned(RPC_GARBAGE);
   1240  1.1.1.2  fvdl 			break;
   1241      1.1   cgd 		default:
   1242      1.1   cgd 			*tl = 0;
   1243  1.1.1.2  fvdl 			if (err != NFSERR_RETVOID) {
   1244      1.1   cgd 				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
   1245  1.1.1.2  fvdl 				if (err)
   1246  1.1.1.2  fvdl 				    *tl = txdr_unsigned(nfsrv_errmap(nd, err));
   1247  1.1.1.2  fvdl 				else
   1248  1.1.1.2  fvdl 				    *tl = 0;
   1249      1.1   cgd 			}
   1250      1.1   cgd 			break;
   1251      1.1   cgd 		};
   1252      1.1   cgd 	}
   1253  1.1.1.2  fvdl 
   1254  1.1.1.2  fvdl 	/*
   1255  1.1.1.2  fvdl 	 * For nqnfs, piggyback lease as requested.
   1256  1.1.1.2  fvdl 	 */
   1257  1.1.1.2  fvdl 	if ((nd->nd_flag & ND_NQNFS) && err == 0) {
   1258  1.1.1.2  fvdl 		if (nd->nd_flag & ND_LEASE) {
   1259  1.1.1.2  fvdl 			nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
   1260  1.1.1.2  fvdl 			*tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE);
   1261  1.1.1.2  fvdl 			*tl++ = txdr_unsigned(cache);
   1262  1.1.1.2  fvdl 			*tl++ = txdr_unsigned(nd->nd_duration);
   1263  1.1.1.2  fvdl 			txdr_hyper(frev, tl);
   1264  1.1.1.2  fvdl 		} else {
   1265  1.1.1.2  fvdl 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
   1266  1.1.1.2  fvdl 			*tl = 0;
   1267  1.1.1.2  fvdl 		}
   1268  1.1.1.2  fvdl 	}
   1269      1.1   cgd 	*mrq = mreq;
   1270      1.1   cgd 	*mbp = mb;
   1271      1.1   cgd 	*bposp = bpos;
   1272  1.1.1.2  fvdl 	if (err != 0 && err != NFSERR_RETVOID)
   1273      1.1   cgd 		nfsstats.srvrpc_errs++;
   1274      1.1   cgd 	return (0);
   1275      1.1   cgd }
   1276      1.1   cgd 
   1277      1.1   cgd /*
   1278      1.1   cgd  * Nfs timer routine
   1279      1.1   cgd  * Scan the nfsreq list and retranmit any requests that have timed out
   1280      1.1   cgd  * To avoid retransmission attempts on STREAM sockets (in the future) make
   1281      1.1   cgd  * sure to set the r_retry field to 0 (implies nm_retry == 0).
   1282      1.1   cgd  */
   1283  1.1.1.2  fvdl void
   1284  1.1.1.2  fvdl nfs_timer(arg)
   1285  1.1.1.2  fvdl 	void *arg;	/* never used */
   1286      1.1   cgd {
   1287      1.1   cgd 	register struct nfsreq *rep;
   1288      1.1   cgd 	register struct mbuf *m;
   1289      1.1   cgd 	register struct socket *so;
   1290      1.1   cgd 	register struct nfsmount *nmp;
   1291  1.1.1.2  fvdl 	register int timeo;
   1292  1.1.1.2  fvdl 	register struct nfssvc_sock *slp;
   1293  1.1.1.2  fvdl 	static long lasttime = 0;
   1294      1.1   cgd 	int s, error;
   1295  1.1.1.2  fvdl 	u_quad_t cur_usec;
   1296      1.1   cgd 
   1297      1.1   cgd 	s = splnet();
   1298  1.1.1.2  fvdl 	for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) {
   1299      1.1   cgd 		nmp = rep->r_nmp;
   1300  1.1.1.2  fvdl 		if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
   1301      1.1   cgd 			continue;
   1302  1.1.1.2  fvdl 		if (nfs_sigintr(nmp, rep, rep->r_procp)) {
   1303      1.1   cgd 			rep->r_flags |= R_SOFTTERM;
   1304      1.1   cgd 			continue;
   1305      1.1   cgd 		}
   1306  1.1.1.2  fvdl 		if (rep->r_rtt >= 0) {
   1307  1.1.1.2  fvdl 			rep->r_rtt++;
   1308  1.1.1.2  fvdl 			if (nmp->nm_flag & NFSMNT_DUMBTIMR)
   1309  1.1.1.2  fvdl 				timeo = nmp->nm_timeo;
   1310  1.1.1.2  fvdl 			else
   1311  1.1.1.2  fvdl 				timeo = NFS_RTO(nmp, proct[rep->r_procnum]);
   1312  1.1.1.2  fvdl 			if (nmp->nm_timeouts > 0)
   1313  1.1.1.2  fvdl 				timeo *= nfs_backoff[nmp->nm_timeouts - 1];
   1314  1.1.1.2  fvdl 			if (rep->r_rtt <= timeo)
   1315  1.1.1.2  fvdl 				continue;
   1316  1.1.1.2  fvdl 			if (nmp->nm_timeouts < 8)
   1317  1.1.1.2  fvdl 				nmp->nm_timeouts++;
   1318      1.1   cgd 		}
   1319      1.1   cgd 		/*
   1320      1.1   cgd 		 * Check for server not responding
   1321      1.1   cgd 		 */
   1322      1.1   cgd 		if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
   1323  1.1.1.2  fvdl 		     rep->r_rexmit > nmp->nm_deadthresh) {
   1324      1.1   cgd 			nfs_msg(rep->r_procp,
   1325      1.1   cgd 			    nmp->nm_mountp->mnt_stat.f_mntfromname,
   1326      1.1   cgd 			    "not responding");
   1327      1.1   cgd 			rep->r_flags |= R_TPRINTFMSG;
   1328      1.1   cgd 		}
   1329      1.1   cgd 		if (rep->r_rexmit >= rep->r_retry) {	/* too many */
   1330      1.1   cgd 			nfsstats.rpctimeouts++;
   1331      1.1   cgd 			rep->r_flags |= R_SOFTTERM;
   1332      1.1   cgd 			continue;
   1333      1.1   cgd 		}
   1334  1.1.1.2  fvdl 		if (nmp->nm_sotype != SOCK_DGRAM) {
   1335  1.1.1.2  fvdl 			if (++rep->r_rexmit > NFS_MAXREXMIT)
   1336  1.1.1.2  fvdl 				rep->r_rexmit = NFS_MAXREXMIT;
   1337  1.1.1.2  fvdl 			continue;
   1338  1.1.1.2  fvdl 		}
   1339  1.1.1.2  fvdl 		if ((so = nmp->nm_so) == NULL)
   1340      1.1   cgd 			continue;
   1341      1.1   cgd 
   1342      1.1   cgd 		/*
   1343      1.1   cgd 		 * If there is enough space and the window allows..
   1344      1.1   cgd 		 *	Resend it
   1345  1.1.1.2  fvdl 		 * Set r_rtt to -1 in case we fail to send it now.
   1346      1.1   cgd 		 */
   1347  1.1.1.2  fvdl 		rep->r_rtt = -1;
   1348      1.1   cgd 		if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
   1349  1.1.1.2  fvdl 		   ((nmp->nm_flag & NFSMNT_DUMBTIMR) ||
   1350  1.1.1.2  fvdl 		    (rep->r_flags & R_SENT) ||
   1351  1.1.1.2  fvdl 		    nmp->nm_sent < nmp->nm_cwnd) &&
   1352  1.1.1.2  fvdl 		   (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
   1353      1.1   cgd 			if ((nmp->nm_flag & NFSMNT_NOCONN) == 0)
   1354      1.1   cgd 			    error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
   1355  1.1.1.2  fvdl 			    (struct mbuf *)0, (struct mbuf *)0);
   1356      1.1   cgd 			else
   1357      1.1   cgd 			    error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
   1358  1.1.1.2  fvdl 			    nmp->nm_nam, (struct mbuf *)0);
   1359      1.1   cgd 			if (error) {
   1360      1.1   cgd 				if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
   1361      1.1   cgd 					so->so_error = 0;
   1362      1.1   cgd 			} else {
   1363      1.1   cgd 				/*
   1364  1.1.1.2  fvdl 				 * Iff first send, start timing
   1365  1.1.1.2  fvdl 				 * else turn timing off, backoff timer
   1366  1.1.1.2  fvdl 				 * and divide congestion window by 2.
   1367      1.1   cgd 				 */
   1368  1.1.1.2  fvdl 				if (rep->r_flags & R_SENT) {
   1369  1.1.1.2  fvdl 					rep->r_flags &= ~R_TIMING;
   1370  1.1.1.2  fvdl 					if (++rep->r_rexmit > NFS_MAXREXMIT)
   1371  1.1.1.2  fvdl 						rep->r_rexmit = NFS_MAXREXMIT;
   1372  1.1.1.2  fvdl 					nmp->nm_cwnd >>= 1;
   1373  1.1.1.2  fvdl 					if (nmp->nm_cwnd < NFS_CWNDSCALE)
   1374  1.1.1.2  fvdl 						nmp->nm_cwnd = NFS_CWNDSCALE;
   1375  1.1.1.2  fvdl 					nfsstats.rpcretries++;
   1376  1.1.1.2  fvdl 				} else {
   1377  1.1.1.2  fvdl 					rep->r_flags |= R_SENT;
   1378  1.1.1.2  fvdl 					nmp->nm_sent += NFS_CWNDSCALE;
   1379  1.1.1.2  fvdl 				}
   1380  1.1.1.2  fvdl 				rep->r_rtt = 0;
   1381      1.1   cgd 			}
   1382      1.1   cgd 		}
   1383      1.1   cgd 	}
   1384  1.1.1.2  fvdl 
   1385  1.1.1.2  fvdl 	/*
   1386  1.1.1.2  fvdl 	 * Call the nqnfs server timer once a second to handle leases.
   1387  1.1.1.2  fvdl 	 */
   1388  1.1.1.2  fvdl 	if (lasttime != time.tv_sec) {
   1389  1.1.1.2  fvdl 		lasttime = time.tv_sec;
   1390  1.1.1.2  fvdl 		nqnfs_serverd();
   1391  1.1.1.2  fvdl 	}
   1392  1.1.1.2  fvdl 
   1393  1.1.1.2  fvdl 	/*
   1394  1.1.1.2  fvdl 	 * Scan the write gathering queues for writes that need to be
   1395  1.1.1.2  fvdl 	 * completed now.
   1396  1.1.1.2  fvdl 	 */
   1397  1.1.1.2  fvdl 	cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
   1398  1.1.1.2  fvdl 	for (slp = nfssvc_sockhead.tqh_first; slp != 0;
   1399  1.1.1.2  fvdl 	    slp = slp->ns_chain.tqe_next) {
   1400  1.1.1.2  fvdl 	    if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec)
   1401  1.1.1.2  fvdl 		nfsrv_wakenfsd(slp);
   1402  1.1.1.2  fvdl 	}
   1403      1.1   cgd 	splx(s);
   1404  1.1.1.2  fvdl 	timeout(nfs_timer, (void *)0, nfs_ticks);
   1405      1.1   cgd }
   1406      1.1   cgd 
   1407      1.1   cgd /*
   1408  1.1.1.2  fvdl  * Test for a termination condition pending on the process.
   1409  1.1.1.2  fvdl  * This is used for NFSMNT_INT mounts.
   1410      1.1   cgd  */
   1411  1.1.1.2  fvdl int
   1412  1.1.1.2  fvdl nfs_sigintr(nmp, rep, p)
   1413  1.1.1.2  fvdl 	struct nfsmount *nmp;
   1414  1.1.1.2  fvdl 	struct nfsreq *rep;
   1415  1.1.1.2  fvdl 	register struct proc *p;
   1416  1.1.1.2  fvdl {
   1417  1.1.1.2  fvdl 
   1418  1.1.1.2  fvdl 	if (rep && (rep->r_flags & R_SOFTTERM))
   1419  1.1.1.2  fvdl 		return (EINTR);
   1420  1.1.1.2  fvdl 	if (!(nmp->nm_flag & NFSMNT_INT))
   1421  1.1.1.2  fvdl 		return (0);
   1422  1.1.1.2  fvdl 	if (p && p->p_siglist &&
   1423  1.1.1.2  fvdl 	    (((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) &
   1424  1.1.1.2  fvdl 	    NFSINT_SIGMASK))
   1425  1.1.1.2  fvdl 		return (EINTR);
   1426  1.1.1.2  fvdl 	return (0);
   1427  1.1.1.2  fvdl }
   1428      1.1   cgd 
   1429      1.1   cgd /*
   1430  1.1.1.2  fvdl  * Lock a socket against others.
   1431  1.1.1.2  fvdl  * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
   1432  1.1.1.2  fvdl  * and also to avoid race conditions between the processes with nfs requests
   1433  1.1.1.2  fvdl  * in progress when a reconnect is necessary.
   1434      1.1   cgd  */
   1435  1.1.1.2  fvdl int
   1436  1.1.1.2  fvdl nfs_sndlock(flagp, rep)
   1437  1.1.1.2  fvdl 	register int *flagp;
   1438  1.1.1.2  fvdl 	struct nfsreq *rep;
   1439  1.1.1.2  fvdl {
   1440  1.1.1.2  fvdl 	struct proc *p;
   1441  1.1.1.2  fvdl 	int slpflag = 0, slptimeo = 0;
   1442      1.1   cgd 
   1443  1.1.1.2  fvdl 	if (rep) {
   1444  1.1.1.2  fvdl 		p = rep->r_procp;
   1445  1.1.1.2  fvdl 		if (rep->r_nmp->nm_flag & NFSMNT_INT)
   1446  1.1.1.2  fvdl 			slpflag = PCATCH;
   1447  1.1.1.2  fvdl 	} else
   1448  1.1.1.2  fvdl 		p = (struct proc *)0;
   1449  1.1.1.2  fvdl 	while (*flagp & NFSMNT_SNDLOCK) {
   1450  1.1.1.2  fvdl 		if (nfs_sigintr(rep->r_nmp, rep, p))
   1451  1.1.1.2  fvdl 			return (EINTR);
   1452  1.1.1.2  fvdl 		*flagp |= NFSMNT_WANTSND;
   1453  1.1.1.2  fvdl 		(void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsndlck",
   1454  1.1.1.2  fvdl 			slptimeo);
   1455  1.1.1.2  fvdl 		if (slpflag == PCATCH) {
   1456  1.1.1.2  fvdl 			slpflag = 0;
   1457  1.1.1.2  fvdl 			slptimeo = 2 * hz;
   1458  1.1.1.2  fvdl 		}
   1459  1.1.1.2  fvdl 	}
   1460  1.1.1.2  fvdl 	*flagp |= NFSMNT_SNDLOCK;
   1461  1.1.1.2  fvdl 	return (0);
   1462  1.1.1.2  fvdl }
   1463  1.1.1.2  fvdl 
   1464  1.1.1.2  fvdl /*
   1465  1.1.1.2  fvdl  * Unlock the stream socket for others.
   1466  1.1.1.2  fvdl  */
   1467  1.1.1.2  fvdl void
   1468  1.1.1.2  fvdl nfs_sndunlock(flagp)
   1469  1.1.1.2  fvdl 	register int *flagp;
   1470      1.1   cgd {
   1471      1.1   cgd 
   1472  1.1.1.2  fvdl 	if ((*flagp & NFSMNT_SNDLOCK) == 0)
   1473  1.1.1.2  fvdl 		panic("nfs sndunlock");
   1474  1.1.1.2  fvdl 	*flagp &= ~NFSMNT_SNDLOCK;
   1475  1.1.1.2  fvdl 	if (*flagp & NFSMNT_WANTSND) {
   1476  1.1.1.2  fvdl 		*flagp &= ~NFSMNT_WANTSND;
   1477  1.1.1.2  fvdl 		wakeup((caddr_t)flagp);
   1478      1.1   cgd 	}
   1479  1.1.1.2  fvdl }
   1480  1.1.1.2  fvdl 
   1481  1.1.1.2  fvdl int
   1482  1.1.1.2  fvdl nfs_rcvlock(rep)
   1483  1.1.1.2  fvdl 	register struct nfsreq *rep;
   1484  1.1.1.2  fvdl {
   1485  1.1.1.2  fvdl 	register int *flagp = &rep->r_nmp->nm_flag;
   1486  1.1.1.2  fvdl 	int slpflag, slptimeo = 0;
   1487  1.1.1.2  fvdl 
   1488  1.1.1.2  fvdl 	if (*flagp & NFSMNT_INT)
   1489  1.1.1.2  fvdl 		slpflag = PCATCH;
   1490  1.1.1.2  fvdl 	else
   1491  1.1.1.2  fvdl 		slpflag = 0;
   1492  1.1.1.2  fvdl 	while (*flagp & NFSMNT_RCVLOCK) {
   1493  1.1.1.2  fvdl 		if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp))
   1494  1.1.1.2  fvdl 			return (EINTR);
   1495  1.1.1.2  fvdl 		*flagp |= NFSMNT_WANTRCV;
   1496  1.1.1.2  fvdl 		(void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsrcvlk",
   1497  1.1.1.2  fvdl 			slptimeo);
   1498  1.1.1.2  fvdl 		if (slpflag == PCATCH) {
   1499  1.1.1.2  fvdl 			slpflag = 0;
   1500  1.1.1.2  fvdl 			slptimeo = 2 * hz;
   1501      1.1   cgd 		}
   1502      1.1   cgd 	}
   1503  1.1.1.2  fvdl 	*flagp |= NFSMNT_RCVLOCK;
   1504  1.1.1.2  fvdl 	return (0);
   1505      1.1   cgd }
   1506      1.1   cgd 
   1507  1.1.1.2  fvdl /*
   1508  1.1.1.2  fvdl  * Unlock the stream socket for others.
   1509  1.1.1.2  fvdl  */
   1510  1.1.1.2  fvdl void
   1511  1.1.1.2  fvdl nfs_rcvunlock(flagp)
   1512  1.1.1.2  fvdl 	register int *flagp;
   1513      1.1   cgd {
   1514      1.1   cgd 
   1515  1.1.1.2  fvdl 	if ((*flagp & NFSMNT_RCVLOCK) == 0)
   1516  1.1.1.2  fvdl 		panic("nfs rcvunlock");
   1517  1.1.1.2  fvdl 	*flagp &= ~NFSMNT_RCVLOCK;
   1518  1.1.1.2  fvdl 	if (*flagp & NFSMNT_WANTRCV) {
   1519  1.1.1.2  fvdl 		*flagp &= ~NFSMNT_WANTRCV;
   1520  1.1.1.2  fvdl 		wakeup((caddr_t)flagp);
   1521      1.1   cgd 	}
   1522      1.1   cgd }
   1523      1.1   cgd 
   1524      1.1   cgd /*
   1525  1.1.1.2  fvdl  * Check for badly aligned mbuf data areas and
   1526  1.1.1.2  fvdl  * realign data in an mbuf list by copying the data areas up, as required.
   1527      1.1   cgd  */
   1528  1.1.1.2  fvdl void
   1529  1.1.1.2  fvdl nfs_realign(m, hsiz)
   1530  1.1.1.2  fvdl 	register struct mbuf *m;
   1531  1.1.1.2  fvdl 	int hsiz;
   1532      1.1   cgd {
   1533  1.1.1.2  fvdl 	register struct mbuf *m2;
   1534  1.1.1.2  fvdl 	register int siz, mlen, olen;
   1535  1.1.1.2  fvdl 	register caddr_t tcp, fcp;
   1536  1.1.1.2  fvdl 	struct mbuf *mnew;
   1537  1.1.1.2  fvdl 
   1538  1.1.1.2  fvdl 	while (m) {
   1539  1.1.1.2  fvdl 	    /*
   1540  1.1.1.2  fvdl 	     * This never happens for UDP, rarely happens for TCP
   1541  1.1.1.2  fvdl 	     * but frequently happens for iso transport.
   1542  1.1.1.2  fvdl 	     */
   1543  1.1.1.2  fvdl 	    if ((m->m_len & 0x3) || (mtod(m, int) & 0x3)) {
   1544  1.1.1.2  fvdl 		olen = m->m_len;
   1545  1.1.1.2  fvdl 		fcp = mtod(m, caddr_t);
   1546  1.1.1.2  fvdl 		if ((int)fcp & 0x3) {
   1547  1.1.1.2  fvdl 			m->m_flags &= ~M_PKTHDR;
   1548  1.1.1.2  fvdl 			if (m->m_flags & M_EXT)
   1549  1.1.1.2  fvdl 				m->m_data = m->m_ext.ext_buf +
   1550  1.1.1.2  fvdl 					((m->m_ext.ext_size - olen) & ~0x3);
   1551  1.1.1.2  fvdl 			else
   1552  1.1.1.2  fvdl 				m->m_data = m->m_dat;
   1553  1.1.1.2  fvdl 		}
   1554  1.1.1.2  fvdl 		m->m_len = 0;
   1555  1.1.1.2  fvdl 		tcp = mtod(m, caddr_t);
   1556  1.1.1.2  fvdl 		mnew = m;
   1557  1.1.1.2  fvdl 		m2 = m->m_next;
   1558  1.1.1.2  fvdl 
   1559  1.1.1.2  fvdl 		/*
   1560  1.1.1.2  fvdl 		 * If possible, only put the first invariant part
   1561  1.1.1.2  fvdl 		 * of the RPC header in the first mbuf.
   1562  1.1.1.2  fvdl 		 */
   1563  1.1.1.2  fvdl 		mlen = M_TRAILINGSPACE(m);
   1564  1.1.1.2  fvdl 		if (olen <= hsiz && mlen > hsiz)
   1565  1.1.1.2  fvdl 			mlen = hsiz;
   1566  1.1.1.2  fvdl 
   1567  1.1.1.2  fvdl 		/*
   1568  1.1.1.2  fvdl 		 * Loop through the mbuf list consolidating data.
   1569  1.1.1.2  fvdl 		 */
   1570  1.1.1.2  fvdl 		while (m) {
   1571  1.1.1.2  fvdl 			while (olen > 0) {
   1572  1.1.1.2  fvdl 				if (mlen == 0) {
   1573  1.1.1.2  fvdl 					m2->m_flags &= ~M_PKTHDR;
   1574  1.1.1.2  fvdl 					if (m2->m_flags & M_EXT)
   1575  1.1.1.2  fvdl 						m2->m_data = m2->m_ext.ext_buf;
   1576  1.1.1.2  fvdl 					else
   1577  1.1.1.2  fvdl 						m2->m_data = m2->m_dat;
   1578  1.1.1.2  fvdl 					m2->m_len = 0;
   1579  1.1.1.2  fvdl 					mlen = M_TRAILINGSPACE(m2);
   1580  1.1.1.2  fvdl 					tcp = mtod(m2, caddr_t);
   1581  1.1.1.2  fvdl 					mnew = m2;
   1582  1.1.1.2  fvdl 					m2 = m2->m_next;
   1583  1.1.1.2  fvdl 				}
   1584  1.1.1.2  fvdl 				siz = min(mlen, olen);
   1585  1.1.1.2  fvdl 				if (tcp != fcp)
   1586  1.1.1.2  fvdl 					bcopy(fcp, tcp, siz);
   1587  1.1.1.2  fvdl 				mnew->m_len += siz;
   1588  1.1.1.2  fvdl 				mlen -= siz;
   1589  1.1.1.2  fvdl 				olen -= siz;
   1590  1.1.1.2  fvdl 				tcp += siz;
   1591  1.1.1.2  fvdl 				fcp += siz;
   1592  1.1.1.2  fvdl 			}
   1593  1.1.1.2  fvdl 			m = m->m_next;
   1594  1.1.1.2  fvdl 			if (m) {
   1595  1.1.1.2  fvdl 				olen = m->m_len;
   1596  1.1.1.2  fvdl 				fcp = mtod(m, caddr_t);
   1597  1.1.1.2  fvdl 			}
   1598  1.1.1.2  fvdl 		}
   1599  1.1.1.2  fvdl 
   1600  1.1.1.2  fvdl 		/*
   1601  1.1.1.2  fvdl 		 * Finally, set m_len == 0 for any trailing mbufs that have
   1602  1.1.1.2  fvdl 		 * been copied out of.
   1603  1.1.1.2  fvdl 		 */
   1604  1.1.1.2  fvdl 		while (m2) {
   1605  1.1.1.2  fvdl 			m2->m_len = 0;
   1606  1.1.1.2  fvdl 			m2 = m2->m_next;
   1607  1.1.1.2  fvdl 		}
   1608  1.1.1.2  fvdl 		return;
   1609  1.1.1.2  fvdl 	    }
   1610  1.1.1.2  fvdl 	    m = m->m_next;
   1611  1.1.1.2  fvdl 	}
   1612      1.1   cgd }
   1613      1.1   cgd 
   1614  1.1.1.2  fvdl /*
   1615  1.1.1.2  fvdl  * Socket upcall routine for the nfsd sockets.
   1616  1.1.1.2  fvdl  * The caddr_t arg is a pointer to the "struct nfssvc_sock".
   1617  1.1.1.2  fvdl  * Essentially do as much as possible non-blocking, else punt and it will
   1618  1.1.1.2  fvdl  * be called with M_WAIT from an nfsd.
   1619  1.1.1.2  fvdl  */
   1620  1.1.1.2  fvdl void
   1621  1.1.1.2  fvdl nfsrv_rcv(so, arg, waitflag)
   1622  1.1.1.2  fvdl 	struct socket *so;
   1623  1.1.1.2  fvdl 	caddr_t arg;
   1624  1.1.1.2  fvdl 	int waitflag;
   1625      1.1   cgd {
   1626  1.1.1.2  fvdl 	register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg;
   1627  1.1.1.2  fvdl 	register struct mbuf *m;
   1628  1.1.1.2  fvdl 	struct mbuf *mp, *nam;
   1629  1.1.1.2  fvdl 	struct uio auio;
   1630  1.1.1.2  fvdl 	int flags, error;
   1631      1.1   cgd 
   1632  1.1.1.2  fvdl 	if ((slp->ns_flag & SLP_VALID) == 0)
   1633  1.1.1.2  fvdl 		return;
   1634  1.1.1.2  fvdl #ifdef notdef
   1635  1.1.1.2  fvdl 	/*
   1636  1.1.1.2  fvdl 	 * Define this to test for nfsds handling this under heavy load.
   1637  1.1.1.2  fvdl 	 */
   1638  1.1.1.2  fvdl 	if (waitflag == M_DONTWAIT) {
   1639  1.1.1.2  fvdl 		slp->ns_flag |= SLP_NEEDQ; goto dorecs;
   1640  1.1.1.2  fvdl 	}
   1641  1.1.1.2  fvdl #endif
   1642  1.1.1.2  fvdl 	auio.uio_procp = NULL;
   1643  1.1.1.2  fvdl 	if (so->so_type == SOCK_STREAM) {
   1644  1.1.1.2  fvdl 		/*
   1645  1.1.1.2  fvdl 		 * If there are already records on the queue, defer soreceive()
   1646  1.1.1.2  fvdl 		 * to an nfsd so that there is feedback to the TCP layer that
   1647  1.1.1.2  fvdl 		 * the nfs servers are heavily loaded.
   1648  1.1.1.2  fvdl 		 */
   1649  1.1.1.2  fvdl 		if (slp->ns_rec && waitflag == M_DONTWAIT) {
   1650  1.1.1.2  fvdl 			slp->ns_flag |= SLP_NEEDQ;
   1651  1.1.1.2  fvdl 			goto dorecs;
   1652  1.1.1.2  fvdl 		}
   1653  1.1.1.2  fvdl 
   1654  1.1.1.2  fvdl 		/*
   1655  1.1.1.2  fvdl 		 * Do soreceive().
   1656  1.1.1.2  fvdl 		 */
   1657  1.1.1.2  fvdl 		auio.uio_resid = 1000000000;
   1658  1.1.1.2  fvdl 		flags = MSG_DONTWAIT;
   1659  1.1.1.2  fvdl 		error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags);
   1660  1.1.1.2  fvdl 		if (error || mp == (struct mbuf *)0) {
   1661  1.1.1.2  fvdl 			if (error == EWOULDBLOCK)
   1662  1.1.1.2  fvdl 				slp->ns_flag |= SLP_NEEDQ;
   1663  1.1.1.2  fvdl 			else
   1664  1.1.1.2  fvdl 				slp->ns_flag |= SLP_DISCONN;
   1665  1.1.1.2  fvdl 			goto dorecs;
   1666  1.1.1.2  fvdl 		}
   1667  1.1.1.2  fvdl 		m = mp;
   1668  1.1.1.2  fvdl 		if (slp->ns_rawend) {
   1669  1.1.1.2  fvdl 			slp->ns_rawend->m_next = m;
   1670  1.1.1.2  fvdl 			slp->ns_cc += 1000000000 - auio.uio_resid;
   1671  1.1.1.2  fvdl 		} else {
   1672  1.1.1.2  fvdl 			slp->ns_raw = m;
   1673  1.1.1.2  fvdl 			slp->ns_cc = 1000000000 - auio.uio_resid;
   1674  1.1.1.2  fvdl 		}
   1675  1.1.1.2  fvdl 		while (m->m_next)
   1676  1.1.1.2  fvdl 			m = m->m_next;
   1677  1.1.1.2  fvdl 		slp->ns_rawend = m;
   1678  1.1.1.2  fvdl 
   1679  1.1.1.2  fvdl 		/*
   1680  1.1.1.2  fvdl 		 * Now try and parse record(s) out of the raw stream data.
   1681  1.1.1.2  fvdl 		 */
   1682  1.1.1.2  fvdl 		error = nfsrv_getstream(slp, waitflag);
   1683  1.1.1.2  fvdl 		if (error) {
   1684  1.1.1.2  fvdl 			if (error == EPERM)
   1685  1.1.1.2  fvdl 				slp->ns_flag |= SLP_DISCONN;
   1686  1.1.1.2  fvdl 			else
   1687  1.1.1.2  fvdl 				slp->ns_flag |= SLP_NEEDQ;
   1688  1.1.1.2  fvdl 		}
   1689  1.1.1.2  fvdl 	} else {
   1690  1.1.1.2  fvdl 		do {
   1691  1.1.1.2  fvdl 			auio.uio_resid = 1000000000;
   1692  1.1.1.2  fvdl 			flags = MSG_DONTWAIT;
   1693  1.1.1.2  fvdl 			error = soreceive(so, &nam, &auio, &mp,
   1694  1.1.1.2  fvdl 						(struct mbuf **)0, &flags);
   1695  1.1.1.2  fvdl 			if (mp) {
   1696  1.1.1.2  fvdl 				nfs_realign(mp, 10 * NFSX_UNSIGNED);
   1697  1.1.1.2  fvdl 				if (nam) {
   1698  1.1.1.2  fvdl 					m = nam;
   1699  1.1.1.2  fvdl 					m->m_next = mp;
   1700  1.1.1.2  fvdl 				} else
   1701  1.1.1.2  fvdl 					m = mp;
   1702  1.1.1.2  fvdl 				if (slp->ns_recend)
   1703  1.1.1.2  fvdl 					slp->ns_recend->m_nextpkt = m;
   1704  1.1.1.2  fvdl 				else
   1705  1.1.1.2  fvdl 					slp->ns_rec = m;
   1706  1.1.1.2  fvdl 				slp->ns_recend = m;
   1707  1.1.1.2  fvdl 				m->m_nextpkt = (struct mbuf *)0;
   1708  1.1.1.2  fvdl 			}
   1709  1.1.1.2  fvdl 			if (error) {
   1710  1.1.1.2  fvdl 				if ((so->so_proto->pr_flags & PR_CONNREQUIRED)
   1711  1.1.1.2  fvdl 					&& error != EWOULDBLOCK) {
   1712  1.1.1.2  fvdl 					slp->ns_flag |= SLP_DISCONN;
   1713  1.1.1.2  fvdl 					goto dorecs;
   1714  1.1.1.2  fvdl 				}
   1715  1.1.1.2  fvdl 			}
   1716  1.1.1.2  fvdl 		} while (mp);
   1717  1.1.1.2  fvdl 	}
   1718  1.1.1.2  fvdl 
   1719  1.1.1.2  fvdl 	/*
   1720  1.1.1.2  fvdl 	 * Now try and process the request records, non-blocking.
   1721  1.1.1.2  fvdl 	 */
   1722  1.1.1.2  fvdl dorecs:
   1723  1.1.1.2  fvdl 	if (waitflag == M_DONTWAIT &&
   1724  1.1.1.2  fvdl 		(slp->ns_rec || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN))))
   1725  1.1.1.2  fvdl 		nfsrv_wakenfsd(slp);
   1726      1.1   cgd }
   1727      1.1   cgd 
   1728      1.1   cgd /*
   1729  1.1.1.2  fvdl  * Try and extract an RPC request from the mbuf data list received on a
   1730  1.1.1.2  fvdl  * stream socket. The "waitflag" argument indicates whether or not it
   1731  1.1.1.2  fvdl  * can sleep.
   1732      1.1   cgd  */
   1733  1.1.1.2  fvdl int
   1734  1.1.1.2  fvdl nfsrv_getstream(slp, waitflag)
   1735  1.1.1.2  fvdl 	register struct nfssvc_sock *slp;
   1736  1.1.1.2  fvdl 	int waitflag;
   1737      1.1   cgd {
   1738  1.1.1.2  fvdl 	register struct mbuf *m, **mpp;
   1739  1.1.1.2  fvdl 	register char *cp1, *cp2;
   1740  1.1.1.2  fvdl 	register int len;
   1741  1.1.1.2  fvdl 	struct mbuf *om, *m2, *recm = 0;
   1742  1.1.1.2  fvdl 	u_long recmark;
   1743      1.1   cgd 
   1744  1.1.1.2  fvdl 	if (slp->ns_flag & SLP_GETSTREAM)
   1745  1.1.1.2  fvdl 		panic("nfs getstream");
   1746  1.1.1.2  fvdl 	slp->ns_flag |= SLP_GETSTREAM;
   1747  1.1.1.2  fvdl 	for (;;) {
   1748  1.1.1.2  fvdl 	    if (slp->ns_reclen == 0) {
   1749  1.1.1.2  fvdl 		if (slp->ns_cc < NFSX_UNSIGNED) {
   1750  1.1.1.2  fvdl 			slp->ns_flag &= ~SLP_GETSTREAM;
   1751  1.1.1.2  fvdl 			return (0);
   1752  1.1.1.2  fvdl 		}
   1753  1.1.1.2  fvdl 		m = slp->ns_raw;
   1754  1.1.1.2  fvdl 		if (m->m_len >= NFSX_UNSIGNED) {
   1755  1.1.1.2  fvdl 			bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED);
   1756  1.1.1.2  fvdl 			m->m_data += NFSX_UNSIGNED;
   1757  1.1.1.2  fvdl 			m->m_len -= NFSX_UNSIGNED;
   1758  1.1.1.2  fvdl 		} else {
   1759  1.1.1.2  fvdl 			cp1 = (caddr_t)&recmark;
   1760  1.1.1.2  fvdl 			cp2 = mtod(m, caddr_t);
   1761  1.1.1.2  fvdl 			while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) {
   1762  1.1.1.2  fvdl 				while (m->m_len == 0) {
   1763  1.1.1.2  fvdl 					m = m->m_next;
   1764  1.1.1.2  fvdl 					cp2 = mtod(m, caddr_t);
   1765  1.1.1.2  fvdl 				}
   1766  1.1.1.2  fvdl 				*cp1++ = *cp2++;
   1767  1.1.1.2  fvdl 				m->m_data++;
   1768  1.1.1.2  fvdl 				m->m_len--;
   1769  1.1.1.2  fvdl 			}
   1770  1.1.1.2  fvdl 		}
   1771  1.1.1.2  fvdl 		slp->ns_cc -= NFSX_UNSIGNED;
   1772  1.1.1.2  fvdl 		recmark = ntohl(recmark);
   1773  1.1.1.2  fvdl 		slp->ns_reclen = recmark & ~0x80000000;
   1774  1.1.1.2  fvdl 		if (recmark & 0x80000000)
   1775  1.1.1.2  fvdl 			slp->ns_flag |= SLP_LASTFRAG;
   1776  1.1.1.2  fvdl 		else
   1777  1.1.1.2  fvdl 			slp->ns_flag &= ~SLP_LASTFRAG;
   1778  1.1.1.2  fvdl 		if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) {
   1779  1.1.1.2  fvdl 			slp->ns_flag &= ~SLP_GETSTREAM;
   1780  1.1.1.2  fvdl 			return (EPERM);
   1781  1.1.1.2  fvdl 		}
   1782  1.1.1.2  fvdl 	    }
   1783  1.1.1.2  fvdl 
   1784  1.1.1.2  fvdl 	    /*
   1785  1.1.1.2  fvdl 	     * Now get the record part.
   1786  1.1.1.2  fvdl 	     */
   1787  1.1.1.2  fvdl 	    if (slp->ns_cc == slp->ns_reclen) {
   1788  1.1.1.2  fvdl 		recm = slp->ns_raw;
   1789  1.1.1.2  fvdl 		slp->ns_raw = slp->ns_rawend = (struct mbuf *)0;
   1790  1.1.1.2  fvdl 		slp->ns_cc = slp->ns_reclen = 0;
   1791  1.1.1.2  fvdl 	    } else if (slp->ns_cc > slp->ns_reclen) {
   1792  1.1.1.2  fvdl 		len = 0;
   1793  1.1.1.2  fvdl 		m = slp->ns_raw;
   1794  1.1.1.2  fvdl 		om = (struct mbuf *)0;
   1795  1.1.1.2  fvdl 		while (len < slp->ns_reclen) {
   1796  1.1.1.2  fvdl 			if ((len + m->m_len) > slp->ns_reclen) {
   1797  1.1.1.2  fvdl 				m2 = m_copym(m, 0, slp->ns_reclen - len,
   1798  1.1.1.2  fvdl 					waitflag);
   1799  1.1.1.2  fvdl 				if (m2) {
   1800  1.1.1.2  fvdl 					if (om) {
   1801  1.1.1.2  fvdl 						om->m_next = m2;
   1802  1.1.1.2  fvdl 						recm = slp->ns_raw;
   1803  1.1.1.2  fvdl 					} else
   1804  1.1.1.2  fvdl 						recm = m2;
   1805  1.1.1.2  fvdl 					m->m_data += slp->ns_reclen - len;
   1806  1.1.1.2  fvdl 					m->m_len -= slp->ns_reclen - len;
   1807  1.1.1.2  fvdl 					len = slp->ns_reclen;
   1808  1.1.1.2  fvdl 				} else {
   1809  1.1.1.2  fvdl 					slp->ns_flag &= ~SLP_GETSTREAM;
   1810  1.1.1.2  fvdl 					return (EWOULDBLOCK);
   1811  1.1.1.2  fvdl 				}
   1812  1.1.1.2  fvdl 			} else if ((len + m->m_len) == slp->ns_reclen) {
   1813  1.1.1.2  fvdl 				om = m;
   1814  1.1.1.2  fvdl 				len += m->m_len;
   1815  1.1.1.2  fvdl 				m = m->m_next;
   1816  1.1.1.2  fvdl 				recm = slp->ns_raw;
   1817  1.1.1.2  fvdl 				om->m_next = (struct mbuf *)0;
   1818  1.1.1.2  fvdl 			} else {
   1819  1.1.1.2  fvdl 				om = m;
   1820  1.1.1.2  fvdl 				len += m->m_len;
   1821  1.1.1.2  fvdl 				m = m->m_next;
   1822  1.1.1.2  fvdl 			}
   1823  1.1.1.2  fvdl 		}
   1824  1.1.1.2  fvdl 		slp->ns_raw = m;
   1825  1.1.1.2  fvdl 		slp->ns_cc -= len;
   1826  1.1.1.2  fvdl 		slp->ns_reclen = 0;
   1827  1.1.1.2  fvdl 	    } else {
   1828  1.1.1.2  fvdl 		slp->ns_flag &= ~SLP_GETSTREAM;
   1829  1.1.1.2  fvdl 		return (0);
   1830  1.1.1.2  fvdl 	    }
   1831  1.1.1.2  fvdl 
   1832  1.1.1.2  fvdl 	    /*
   1833  1.1.1.2  fvdl 	     * Accumulate the fragments into a record.
   1834  1.1.1.2  fvdl 	     */
   1835  1.1.1.2  fvdl 	    mpp = &slp->ns_frag;
   1836  1.1.1.2  fvdl 	    while (*mpp)
   1837  1.1.1.2  fvdl 		mpp = &((*mpp)->m_next);
   1838  1.1.1.2  fvdl 	    *mpp = recm;
   1839  1.1.1.2  fvdl 	    if (slp->ns_flag & SLP_LASTFRAG) {
   1840  1.1.1.2  fvdl 		nfs_realign(slp->ns_frag, 10 * NFSX_UNSIGNED);
   1841  1.1.1.2  fvdl 		if (slp->ns_recend)
   1842  1.1.1.2  fvdl 		    slp->ns_recend->m_nextpkt = slp->ns_frag;
   1843  1.1.1.2  fvdl 		else
   1844  1.1.1.2  fvdl 		    slp->ns_rec = slp->ns_frag;
   1845  1.1.1.2  fvdl 		slp->ns_recend = slp->ns_frag;
   1846  1.1.1.2  fvdl 		slp->ns_frag = (struct mbuf *)0;
   1847  1.1.1.2  fvdl 	    }
   1848      1.1   cgd 	}
   1849      1.1   cgd }
   1850      1.1   cgd 
   1851      1.1   cgd /*
   1852  1.1.1.2  fvdl  * Parse an RPC header.
   1853      1.1   cgd  */
   1854  1.1.1.2  fvdl int
   1855  1.1.1.2  fvdl nfsrv_dorec(slp, nfsd, ndp)
   1856  1.1.1.2  fvdl 	register struct nfssvc_sock *slp;
   1857  1.1.1.2  fvdl 	struct nfsd *nfsd;
   1858  1.1.1.2  fvdl 	struct nfsrv_descript **ndp;
   1859      1.1   cgd {
   1860  1.1.1.2  fvdl 	register struct mbuf *m, *nam;
   1861  1.1.1.2  fvdl 	register struct nfsrv_descript *nd;
   1862  1.1.1.2  fvdl 	int error;
   1863      1.1   cgd 
   1864  1.1.1.2  fvdl 	*ndp = NULL;
   1865  1.1.1.2  fvdl 	if ((slp->ns_flag & SLP_VALID) == 0 ||
   1866  1.1.1.2  fvdl 	    (m = slp->ns_rec) == (struct mbuf *)0)
   1867  1.1.1.2  fvdl 		return (ENOBUFS);
   1868  1.1.1.2  fvdl 	slp->ns_rec = m->m_nextpkt;
   1869  1.1.1.2  fvdl 	if (slp->ns_rec)
   1870  1.1.1.2  fvdl 		m->m_nextpkt = (struct mbuf *)0;
   1871  1.1.1.2  fvdl 	else
   1872  1.1.1.2  fvdl 		slp->ns_recend = (struct mbuf *)0;
   1873  1.1.1.2  fvdl 	if (m->m_type == MT_SONAME) {
   1874  1.1.1.2  fvdl 		nam = m;
   1875  1.1.1.2  fvdl 		m = m->m_next;
   1876  1.1.1.2  fvdl 		nam->m_next = NULL;
   1877  1.1.1.2  fvdl 	} else
   1878  1.1.1.2  fvdl 		nam = NULL;
   1879  1.1.1.2  fvdl 	MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript),
   1880  1.1.1.2  fvdl 		M_NFSRVDESC, M_WAITOK);
   1881  1.1.1.2  fvdl 	nd->nd_md = nd->nd_mrep = m;
   1882  1.1.1.2  fvdl 	nd->nd_nam2 = nam;
   1883  1.1.1.2  fvdl 	nd->nd_dpos = mtod(m, caddr_t);
   1884  1.1.1.2  fvdl 	error = nfs_getreq(nd, nfsd, TRUE);
   1885  1.1.1.2  fvdl 	if (error) {
   1886  1.1.1.2  fvdl 		m_freem(nam);
   1887  1.1.1.2  fvdl 		free((caddr_t)nd, M_NFSRVDESC);
   1888  1.1.1.2  fvdl 		return (error);
   1889      1.1   cgd 	}
   1890  1.1.1.2  fvdl 	*ndp = nd;
   1891  1.1.1.2  fvdl 	nfsd->nfsd_nd = nd;
   1892  1.1.1.2  fvdl 	return (0);
   1893      1.1   cgd }
   1894      1.1   cgd 
   1895      1.1   cgd /*
   1896  1.1.1.2  fvdl  * Parse an RPC request
   1897  1.1.1.2  fvdl  * - verify it
   1898  1.1.1.2  fvdl  * - fill in the cred struct.
   1899  1.1.1.2  fvdl  */
   1900  1.1.1.2  fvdl int
   1901  1.1.1.2  fvdl nfs_getreq(nd, nfsd, has_header)
   1902  1.1.1.2  fvdl 	register struct nfsrv_descript *nd;
   1903  1.1.1.2  fvdl 	struct nfsd *nfsd;
   1904  1.1.1.2  fvdl 	int has_header;
   1905  1.1.1.2  fvdl {
   1906  1.1.1.2  fvdl 	register int len, i;
   1907  1.1.1.2  fvdl 	register u_long *tl;
   1908  1.1.1.2  fvdl 	register long t1;
   1909  1.1.1.2  fvdl 	struct uio uio;
   1910  1.1.1.2  fvdl 	struct iovec iov;
   1911  1.1.1.2  fvdl 	caddr_t dpos, cp2, cp;
   1912  1.1.1.2  fvdl 	u_long nfsvers, auth_type;
   1913  1.1.1.2  fvdl 	uid_t nickuid;
   1914  1.1.1.2  fvdl 	int error = 0, nqnfs = 0, ticklen;
   1915  1.1.1.2  fvdl 	struct mbuf *mrep, *md;
   1916  1.1.1.2  fvdl 	register struct nfsuid *nuidp;
   1917  1.1.1.2  fvdl 	struct timeval tvin, tvout;
   1918  1.1.1.2  fvdl 	NFSKERBKEYSCHED_T keys;	/* stores key schedule */
   1919  1.1.1.2  fvdl 
   1920  1.1.1.2  fvdl 	mrep = nd->nd_mrep;
   1921  1.1.1.2  fvdl 	md = nd->nd_md;
   1922  1.1.1.2  fvdl 	dpos = nd->nd_dpos;
   1923  1.1.1.2  fvdl 	if (has_header) {
   1924  1.1.1.2  fvdl 		nfsm_dissect(tl, u_long *, 10 * NFSX_UNSIGNED);
   1925  1.1.1.2  fvdl 		nd->nd_retxid = fxdr_unsigned(u_long, *tl++);
   1926  1.1.1.2  fvdl 		if (*tl++ != rpc_call) {
   1927  1.1.1.2  fvdl 			m_freem(mrep);
   1928  1.1.1.2  fvdl 			return (EBADRPC);
   1929  1.1.1.2  fvdl 		}
   1930  1.1.1.2  fvdl 	} else
   1931  1.1.1.2  fvdl 		nfsm_dissect(tl, u_long *, 8 * NFSX_UNSIGNED);
   1932  1.1.1.2  fvdl 	nd->nd_repstat = 0;
   1933  1.1.1.2  fvdl 	nd->nd_flag = 0;
   1934  1.1.1.2  fvdl 	if (*tl++ != rpc_vers) {
   1935  1.1.1.2  fvdl 		nd->nd_repstat = ERPCMISMATCH;
   1936  1.1.1.2  fvdl 		nd->nd_procnum = NFSPROC_NOOP;
   1937  1.1.1.2  fvdl 		return (0);
   1938  1.1.1.2  fvdl 	}
   1939  1.1.1.2  fvdl 	if (*tl != nfs_prog) {
   1940  1.1.1.2  fvdl 		if (*tl == nqnfs_prog)
   1941  1.1.1.2  fvdl 			nqnfs++;
   1942  1.1.1.2  fvdl 		else {
   1943  1.1.1.2  fvdl 			nd->nd_repstat = EPROGUNAVAIL;
   1944  1.1.1.2  fvdl 			nd->nd_procnum = NFSPROC_NOOP;
   1945  1.1.1.2  fvdl 			return (0);
   1946  1.1.1.2  fvdl 		}
   1947  1.1.1.2  fvdl 	}
   1948  1.1.1.2  fvdl 	tl++;
   1949  1.1.1.2  fvdl 	nfsvers = fxdr_unsigned(u_long, *tl++);
   1950  1.1.1.2  fvdl 	if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) ||
   1951  1.1.1.2  fvdl 		(nfsvers != NQNFS_VER3 && nqnfs)) {
   1952  1.1.1.2  fvdl 		nd->nd_repstat = EPROGMISMATCH;
   1953  1.1.1.2  fvdl 		nd->nd_procnum = NFSPROC_NOOP;
   1954      1.1   cgd 		return (0);
   1955  1.1.1.2  fvdl 	}
   1956  1.1.1.2  fvdl 	if (nqnfs)
   1957  1.1.1.2  fvdl 		nd->nd_flag = (ND_NFSV3 | ND_NQNFS);
   1958  1.1.1.2  fvdl 	else if (nfsvers == NFS_VER3)
   1959  1.1.1.2  fvdl 		nd->nd_flag = ND_NFSV3;
   1960  1.1.1.2  fvdl 	nd->nd_procnum = fxdr_unsigned(u_long, *tl++);
   1961  1.1.1.2  fvdl 	if (nd->nd_procnum == NFSPROC_NULL)
   1962  1.1.1.2  fvdl 		return (0);
   1963  1.1.1.2  fvdl 	if (nd->nd_procnum >= NFS_NPROCS ||
   1964  1.1.1.2  fvdl 		(!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) ||
   1965  1.1.1.2  fvdl 		(!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) {
   1966  1.1.1.2  fvdl 		nd->nd_repstat = EPROCUNAVAIL;
   1967  1.1.1.2  fvdl 		nd->nd_procnum = NFSPROC_NOOP;
   1968  1.1.1.2  fvdl 		return (0);
   1969  1.1.1.2  fvdl 	}
   1970  1.1.1.2  fvdl 	if ((nd->nd_flag & ND_NFSV3) == 0)
   1971  1.1.1.2  fvdl 		nd->nd_procnum = nfsv3_procid[nd->nd_procnum];
   1972  1.1.1.2  fvdl 	auth_type = *tl++;
   1973  1.1.1.2  fvdl 	len = fxdr_unsigned(int, *tl++);
   1974  1.1.1.2  fvdl 	if (len < 0 || len > RPCAUTH_MAXSIZ) {
   1975  1.1.1.2  fvdl 		m_freem(mrep);
   1976  1.1.1.2  fvdl 		return (EBADRPC);
   1977  1.1.1.2  fvdl 	}
   1978      1.1   cgd 
   1979  1.1.1.2  fvdl 	nd->nd_flag &= ~ND_KERBAUTH;
   1980      1.1   cgd 	/*
   1981  1.1.1.2  fvdl 	 * Handle auth_unix or auth_kerb.
   1982      1.1   cgd 	 */
   1983  1.1.1.2  fvdl 	if (auth_type == rpc_auth_unix) {
   1984  1.1.1.2  fvdl 		len = fxdr_unsigned(int, *++tl);
   1985  1.1.1.2  fvdl 		if (len < 0 || len > NFS_MAXNAMLEN) {
   1986  1.1.1.2  fvdl 			m_freem(mrep);
   1987  1.1.1.2  fvdl 			return (EBADRPC);
   1988  1.1.1.2  fvdl 		}
   1989  1.1.1.2  fvdl 		nfsm_adv(nfsm_rndup(len));
   1990  1.1.1.2  fvdl 		nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
   1991  1.1.1.2  fvdl 		bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred));
   1992  1.1.1.2  fvdl 		nd->nd_cr.cr_ref = 1;
   1993  1.1.1.2  fvdl 		nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++);
   1994  1.1.1.2  fvdl 		nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++);
   1995  1.1.1.2  fvdl 		len = fxdr_unsigned(int, *tl);
   1996  1.1.1.2  fvdl 		if (len < 0 || len > RPCAUTH_UNIXGIDS) {
   1997  1.1.1.2  fvdl 			m_freem(mrep);
   1998  1.1.1.2  fvdl 			return (EBADRPC);
   1999  1.1.1.2  fvdl 		}
   2000  1.1.1.2  fvdl 		nfsm_dissect(tl, u_long *, (len + 2) * NFSX_UNSIGNED);
   2001  1.1.1.2  fvdl 		for (i = 1; i <= len; i++)
   2002  1.1.1.2  fvdl 		    if (i < NGROUPS)
   2003  1.1.1.2  fvdl 			nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
   2004  1.1.1.2  fvdl 		    else
   2005  1.1.1.2  fvdl 			tl++;
   2006  1.1.1.2  fvdl 		nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
   2007  1.1.1.2  fvdl 		if (nd->nd_cr.cr_ngroups > 1)
   2008  1.1.1.2  fvdl 		    nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups);
   2009  1.1.1.2  fvdl 		len = fxdr_unsigned(int, *++tl);
   2010  1.1.1.2  fvdl 		if (len < 0 || len > RPCAUTH_MAXSIZ) {
   2011  1.1.1.2  fvdl 			m_freem(mrep);
   2012  1.1.1.2  fvdl 			return (EBADRPC);
   2013  1.1.1.2  fvdl 		}
   2014  1.1.1.2  fvdl 		if (len > 0)
   2015  1.1.1.2  fvdl 			nfsm_adv(nfsm_rndup(len));
   2016  1.1.1.2  fvdl 	} else if (auth_type == rpc_auth_kerb) {
   2017  1.1.1.2  fvdl 		switch (fxdr_unsigned(int, *tl++)) {
   2018  1.1.1.2  fvdl 		case RPCAKN_FULLNAME:
   2019  1.1.1.2  fvdl 			ticklen = fxdr_unsigned(int, *tl);
   2020  1.1.1.2  fvdl 			*((u_long *)nfsd->nfsd_authstr) = *tl;
   2021  1.1.1.2  fvdl 			uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED;
   2022  1.1.1.2  fvdl 			nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED;
   2023  1.1.1.2  fvdl 			if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) {
   2024  1.1.1.2  fvdl 				m_freem(mrep);
   2025  1.1.1.2  fvdl 				return (EBADRPC);
   2026  1.1.1.2  fvdl 			}
   2027  1.1.1.2  fvdl 			uio.uio_offset = 0;
   2028  1.1.1.2  fvdl 			uio.uio_iov = &iov;
   2029  1.1.1.2  fvdl 			uio.uio_iovcnt = 1;
   2030  1.1.1.2  fvdl 			uio.uio_segflg = UIO_SYSSPACE;
   2031  1.1.1.2  fvdl 			iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4];
   2032  1.1.1.2  fvdl 			iov.iov_len = RPCAUTH_MAXSIZ - 4;
   2033  1.1.1.2  fvdl 			nfsm_mtouio(&uio, uio.uio_resid);
   2034  1.1.1.2  fvdl 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
   2035  1.1.1.2  fvdl 			if (*tl++ != rpc_auth_kerb ||
   2036  1.1.1.2  fvdl 				fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) {
   2037  1.1.1.2  fvdl 				printf("Bad kerb verifier\n");
   2038  1.1.1.2  fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
   2039  1.1.1.2  fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   2040  1.1.1.2  fvdl 				return (0);
   2041  1.1.1.2  fvdl 			}
   2042  1.1.1.2  fvdl 			nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED);
   2043  1.1.1.2  fvdl 			tl = (u_long *)cp;
   2044  1.1.1.2  fvdl 			if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) {
   2045  1.1.1.2  fvdl 				printf("Not fullname kerb verifier\n");
   2046  1.1.1.2  fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
   2047  1.1.1.2  fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   2048  1.1.1.2  fvdl 				return (0);
   2049  1.1.1.2  fvdl 			}
   2050  1.1.1.2  fvdl 			cp += NFSX_UNSIGNED;
   2051  1.1.1.2  fvdl 			bcopy(cp, nfsd->nfsd_verfstr, 3 * NFSX_UNSIGNED);
   2052  1.1.1.2  fvdl 			nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED;
   2053  1.1.1.2  fvdl 			nd->nd_flag |= ND_KERBFULL;
   2054  1.1.1.2  fvdl 			nfsd->nfsd_flag |= NFSD_NEEDAUTH;
   2055  1.1.1.2  fvdl 			break;
   2056  1.1.1.2  fvdl 		case RPCAKN_NICKNAME:
   2057  1.1.1.2  fvdl 			if (len != 2 * NFSX_UNSIGNED) {
   2058  1.1.1.2  fvdl 				printf("Kerb nickname short\n");
   2059  1.1.1.2  fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED);
   2060  1.1.1.2  fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   2061  1.1.1.2  fvdl 				return (0);
   2062  1.1.1.2  fvdl 			}
   2063  1.1.1.2  fvdl 			nickuid = fxdr_unsigned(uid_t, *tl);
   2064  1.1.1.2  fvdl 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
   2065  1.1.1.2  fvdl 			if (*tl++ != rpc_auth_kerb ||
   2066  1.1.1.2  fvdl 				fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) {
   2067  1.1.1.2  fvdl 				printf("Kerb nick verifier bad\n");
   2068  1.1.1.2  fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
   2069  1.1.1.2  fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   2070  1.1.1.2  fvdl 				return (0);
   2071  1.1.1.2  fvdl 			}
   2072  1.1.1.2  fvdl 			nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
   2073  1.1.1.2  fvdl 			tvin.tv_sec = *tl++;
   2074  1.1.1.2  fvdl 			tvin.tv_usec = *tl;
   2075  1.1.1.2  fvdl 
   2076  1.1.1.2  fvdl 			for (nuidp = NUIDHASH(nfsd->nfsd_slp,nickuid)->lh_first;
   2077  1.1.1.2  fvdl 			    nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
   2078  1.1.1.2  fvdl 				if (nuidp->nu_cr.cr_uid == nickuid &&
   2079  1.1.1.2  fvdl 				    (!nd->nd_nam2 ||
   2080  1.1.1.2  fvdl 				     netaddr_match(NU_NETFAM(nuidp),
   2081  1.1.1.2  fvdl 				      &nuidp->nu_haddr, nd->nd_nam2)))
   2082  1.1.1.2  fvdl 					break;
   2083  1.1.1.2  fvdl 			}
   2084  1.1.1.2  fvdl 			if (!nuidp) {
   2085  1.1.1.2  fvdl 				nd->nd_repstat =
   2086  1.1.1.2  fvdl 					(NFSERR_AUTHERR|AUTH_REJECTCRED);
   2087  1.1.1.2  fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   2088  1.1.1.2  fvdl 				return (0);
   2089  1.1.1.2  fvdl 			}
   2090  1.1.1.2  fvdl 
   2091  1.1.1.2  fvdl 			/*
   2092  1.1.1.2  fvdl 			 * Now, decrypt the timestamp using the session key
   2093  1.1.1.2  fvdl 			 * and validate it.
   2094  1.1.1.2  fvdl 			 */
   2095  1.1.1.2  fvdl #ifdef NFSKERB
   2096  1.1.1.2  fvdl 			XXX
   2097  1.1.1.2  fvdl #endif
   2098  1.1.1.2  fvdl 
   2099  1.1.1.2  fvdl 			tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec);
   2100  1.1.1.2  fvdl 			tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec);
   2101  1.1.1.2  fvdl 			if (nuidp->nu_expire < time.tv_sec ||
   2102  1.1.1.2  fvdl 			    nuidp->nu_timestamp.tv_sec > tvout.tv_sec ||
   2103  1.1.1.2  fvdl 			    (nuidp->nu_timestamp.tv_sec == tvout.tv_sec &&
   2104  1.1.1.2  fvdl 			     nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) {
   2105  1.1.1.2  fvdl 				nuidp->nu_expire = 0;
   2106  1.1.1.2  fvdl 				nd->nd_repstat =
   2107  1.1.1.2  fvdl 				    (NFSERR_AUTHERR|AUTH_REJECTVERF);
   2108  1.1.1.2  fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   2109  1.1.1.2  fvdl 				return (0);
   2110  1.1.1.2  fvdl 			}
   2111  1.1.1.2  fvdl 			nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr);
   2112  1.1.1.2  fvdl 			nd->nd_flag |= ND_KERBNICK;
   2113  1.1.1.2  fvdl 		};
   2114  1.1.1.2  fvdl 	} else {
   2115  1.1.1.2  fvdl 		nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED);
   2116  1.1.1.2  fvdl 		nd->nd_procnum = NFSPROC_NOOP;
   2117  1.1.1.2  fvdl 		return (0);
   2118  1.1.1.2  fvdl 	}
   2119  1.1.1.2  fvdl 
   2120  1.1.1.2  fvdl 	/*
   2121  1.1.1.2  fvdl 	 * For nqnfs, get piggybacked lease request.
   2122  1.1.1.2  fvdl 	 */
   2123  1.1.1.2  fvdl 	if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) {
   2124  1.1.1.2  fvdl 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
   2125  1.1.1.2  fvdl 		nd->nd_flag |= fxdr_unsigned(int, *tl);
   2126  1.1.1.2  fvdl 		if (nd->nd_flag & ND_LEASE) {
   2127  1.1.1.2  fvdl 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
   2128  1.1.1.2  fvdl 			nd->nd_duration = fxdr_unsigned(int, *tl);
   2129  1.1.1.2  fvdl 		} else
   2130  1.1.1.2  fvdl 			nd->nd_duration = NQ_MINLEASE;
   2131  1.1.1.2  fvdl 	} else
   2132  1.1.1.2  fvdl 		nd->nd_duration = NQ_MINLEASE;
   2133  1.1.1.2  fvdl 	nd->nd_md = md;
   2134  1.1.1.2  fvdl 	nd->nd_dpos = dpos;
   2135      1.1   cgd 	return (0);
   2136  1.1.1.2  fvdl nfsmout:
   2137  1.1.1.2  fvdl 	return (error);
   2138      1.1   cgd }
   2139      1.1   cgd 
   2140      1.1   cgd /*
   2141  1.1.1.2  fvdl  * Search for a sleeping nfsd and wake it up.
   2142  1.1.1.2  fvdl  * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the
   2143  1.1.1.2  fvdl  * running nfsds will go look for the work in the nfssvc_sock list.
   2144  1.1.1.2  fvdl  */
   2145  1.1.1.2  fvdl void
   2146  1.1.1.2  fvdl nfsrv_wakenfsd(slp)
   2147  1.1.1.2  fvdl 	struct nfssvc_sock *slp;
   2148  1.1.1.2  fvdl {
   2149  1.1.1.2  fvdl 	register struct nfsd *nd;
   2150  1.1.1.2  fvdl 
   2151  1.1.1.2  fvdl 	if ((slp->ns_flag & SLP_VALID) == 0)
   2152  1.1.1.2  fvdl 		return;
   2153  1.1.1.2  fvdl 	for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nfsd_chain.tqe_next) {
   2154  1.1.1.2  fvdl 		if (nd->nfsd_flag & NFSD_WAITING) {
   2155  1.1.1.2  fvdl 			nd->nfsd_flag &= ~NFSD_WAITING;
   2156  1.1.1.2  fvdl 			if (nd->nfsd_slp)
   2157  1.1.1.2  fvdl 				panic("nfsd wakeup");
   2158  1.1.1.2  fvdl 			slp->ns_sref++;
   2159  1.1.1.2  fvdl 			nd->nfsd_slp = slp;
   2160  1.1.1.2  fvdl 			wakeup((caddr_t)nd);
   2161  1.1.1.2  fvdl 			return;
   2162  1.1.1.2  fvdl 		}
   2163  1.1.1.2  fvdl 	}
   2164  1.1.1.2  fvdl 	slp->ns_flag |= SLP_DOREC;
   2165  1.1.1.2  fvdl 	nfsd_head_flag |= NFSD_CHECKSLP;
   2166  1.1.1.2  fvdl }
   2167  1.1.1.2  fvdl 
   2168  1.1.1.2  fvdl int
   2169  1.1.1.2  fvdl nfs_msg(p, server, msg)
   2170  1.1.1.2  fvdl 	struct proc *p;
   2171  1.1.1.2  fvdl 	char *server, *msg;
   2172  1.1.1.2  fvdl {
   2173  1.1.1.2  fvdl 	tpr_t tpr;
   2174  1.1.1.2  fvdl 
   2175  1.1.1.2  fvdl 	if (p)
   2176  1.1.1.2  fvdl 		tpr = tprintf_open(p);
   2177  1.1.1.2  fvdl 	else
   2178  1.1.1.2  fvdl 		tpr = NULL;
   2179  1.1.1.2  fvdl 	tprintf(tpr, "nfs server %s: %s\n", server, msg);
   2180  1.1.1.2  fvdl 	tprintf_close(tpr);
   2181  1.1.1.2  fvdl 	return (0);
   2182      1.1   cgd }
   2183