xref: /csrg-svn/sys/nfs/nfs_socket.c (revision 38414)
1*38414Smckusick /*
2*38414Smckusick  * Copyright (c) 1989 The Regents of the University of California.
3*38414Smckusick  * All rights reserved.
4*38414Smckusick  *
5*38414Smckusick  * This code is derived from software contributed to Berkeley by
6*38414Smckusick  * Rick Macklem at The University of Guelph.
7*38414Smckusick  *
8*38414Smckusick  * Redistribution and use in source and binary forms are permitted
9*38414Smckusick  * provided that the above copyright notice and this paragraph are
10*38414Smckusick  * duplicated in all such forms and that any documentation,
11*38414Smckusick  * advertising materials, and other materials related to such
12*38414Smckusick  * distribution and use acknowledge that the software was developed
13*38414Smckusick  * by the University of California, Berkeley.  The name of the
14*38414Smckusick  * University may not be used to endorse or promote products derived
15*38414Smckusick  * from this software without specific prior written permission.
16*38414Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*38414Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*38414Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*38414Smckusick  *
20*38414Smckusick  *	@(#)nfs_socket.c	7.1 (Berkeley) 07/05/89
21*38414Smckusick  */
22*38414Smckusick 
23*38414Smckusick /*
24*38414Smckusick  * Socket operations for use by nfs (similar to uipc_socket.c, but never
25*38414Smckusick  * with copies to/from a uio vector)
26*38414Smckusick  * NB: For now, they only work for UDP datagram sockets.
27*38414Smckusick  * (Use on stream sockets would require some record boundary mark in the
28*38414Smckusick  *  stream such as Sun's RM (Section 3.2 of the Sun RPC Message Protocol
29*38414Smckusick  *  manual, in Networking on the Sun Workstation, Part #800-1324-03
30*38414Smckusick  *  and different versions of send, receive and reply that do not assume
31*38414Smckusick  *  an atomic protocol
32*38414Smckusick  */
33*38414Smckusick 
34*38414Smckusick #include "types.h"
35*38414Smckusick #include "param.h"
36*38414Smckusick #include "uio.h"
37*38414Smckusick #include "user.h"
38*38414Smckusick #include "mount.h"
39*38414Smckusick #include "kernel.h"
40*38414Smckusick #include "malloc.h"
41*38414Smckusick #include "mbuf.h"
42*38414Smckusick #include "vnode.h"
43*38414Smckusick #include "domain.h"
44*38414Smckusick #include "protosw.h"
45*38414Smckusick #include "socket.h"
46*38414Smckusick #include "socketvar.h"
47*38414Smckusick #include "netinet/in.h"
48*38414Smckusick #include "rpcv2.h"
49*38414Smckusick #include "nfsv2.h"
50*38414Smckusick #include "nfs.h"
51*38414Smckusick #include "xdr_subs.h"
52*38414Smckusick #include "nfsm_subs.h"
53*38414Smckusick #include "nfsmount.h"
54*38414Smckusick 
55*38414Smckusick #define	TRUE	1
56*38414Smckusick 
57*38414Smckusick /* set lock on sockbuf sb, sleep at neg prio */
58*38414Smckusick #define nfs_sblock(sb) { \
59*38414Smckusick 	while ((sb)->sb_flags & SB_LOCK) { \
60*38414Smckusick 		(sb)->sb_flags |= SB_WANT; \
61*38414Smckusick 		sleep((caddr_t)&(sb)->sb_flags, PZERO-1); \
62*38414Smckusick 	} \
63*38414Smckusick 	(sb)->sb_flags |= SB_LOCK; \
64*38414Smckusick }
65*38414Smckusick 
66*38414Smckusick /*
67*38414Smckusick  * External data, mostly RPC constants in XDR form
68*38414Smckusick  */
69*38414Smckusick extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
70*38414Smckusick 	rpc_msgaccepted, rpc_call;
71*38414Smckusick extern u_long nfs_prog, nfs_vers;
72*38414Smckusick int	nfsrv_null(),
73*38414Smckusick 	nfsrv_getattr(),
74*38414Smckusick 	nfsrv_setattr(),
75*38414Smckusick 	nfsrv_lookup(),
76*38414Smckusick 	nfsrv_readlink(),
77*38414Smckusick 	nfsrv_read(),
78*38414Smckusick 	nfsrv_write(),
79*38414Smckusick 	nfsrv_create(),
80*38414Smckusick 	nfsrv_remove(),
81*38414Smckusick 	nfsrv_rename(),
82*38414Smckusick 	nfsrv_link(),
83*38414Smckusick 	nfsrv_symlink(),
84*38414Smckusick 	nfsrv_mkdir(),
85*38414Smckusick 	nfsrv_rmdir(),
86*38414Smckusick 	nfsrv_readdir(),
87*38414Smckusick 	nfsrv_statfs(),
88*38414Smckusick 	nfsrv_noop();
89*38414Smckusick 
90*38414Smckusick int (*nfsrv_procs[NFS_NPROCS])() = {
91*38414Smckusick 	nfsrv_null,
92*38414Smckusick 	nfsrv_getattr,
93*38414Smckusick 	nfsrv_setattr,
94*38414Smckusick 	nfsrv_noop,
95*38414Smckusick 	nfsrv_lookup,
96*38414Smckusick 	nfsrv_readlink,
97*38414Smckusick 	nfsrv_read,
98*38414Smckusick 	nfsrv_noop,
99*38414Smckusick 	nfsrv_write,
100*38414Smckusick 	nfsrv_create,
101*38414Smckusick 	nfsrv_remove,
102*38414Smckusick 	nfsrv_rename,
103*38414Smckusick 	nfsrv_link,
104*38414Smckusick 	nfsrv_symlink,
105*38414Smckusick 	nfsrv_mkdir,
106*38414Smckusick 	nfsrv_rmdir,
107*38414Smckusick 	nfsrv_readdir,
108*38414Smckusick 	nfsrv_statfs,
109*38414Smckusick };
110*38414Smckusick 
111*38414Smckusick 
112*38414Smckusick /*
113*38414Smckusick  * This is a stripped down version of sosend() specific to
114*38414Smckusick  * udp/ip and uses the mbuf list provdied
115*38414Smckusick  */
116*38414Smckusick nfs_udpsend(so, nam, top, flags, siz)
117*38414Smckusick 	register struct socket *so;
118*38414Smckusick 	struct mbuf *nam;
119*38414Smckusick 	struct mbuf *top;
120*38414Smckusick 	int flags;
121*38414Smckusick 	int siz;
122*38414Smckusick {
123*38414Smckusick 	register int space;
124*38414Smckusick 	int error = 0, s, dontroute, first = 1;
125*38414Smckusick 
126*38414Smckusick 	dontroute =
127*38414Smckusick 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
128*38414Smckusick 	    (so->so_proto->pr_flags & PR_ATOMIC);
129*38414Smckusick #define	snderr(errno)	{ error = errno; splx(s); goto release; }
130*38414Smckusick 
131*38414Smckusick #ifdef MGETHDR
132*38414Smckusick 	top->m_pkthdr.len = siz;
133*38414Smckusick #endif
134*38414Smckusick restart:
135*38414Smckusick 	nfs_sblock(&so->so_snd);
136*38414Smckusick 	s = splnet();
137*38414Smckusick 	if (so->so_state & SS_CANTSENDMORE)
138*38414Smckusick 		snderr(EPIPE);
139*38414Smckusick 	if (so->so_error)
140*38414Smckusick 		snderr(so->so_error);
141*38414Smckusick 	space = sbspace(&so->so_snd);
142*38414Smckusick 	if (space < siz) {
143*38414Smckusick 		sbunlock(&so->so_snd);
144*38414Smckusick 		nfs_sbwait(&so->so_snd);
145*38414Smckusick 		splx(s);
146*38414Smckusick 		goto restart;
147*38414Smckusick 	}
148*38414Smckusick 	splx(s);
149*38414Smckusick 	if (dontroute)
150*38414Smckusick 		so->so_options |= SO_DONTROUTE;
151*38414Smckusick 	s = splnet();					/* XXX */
152*38414Smckusick 	error = (*so->so_proto->pr_usrreq)(so,
153*38414Smckusick 	    PRU_SEND,
154*38414Smckusick 	    top, (caddr_t)nam, (struct mbuf *)0, (struct mbuf *)0);
155*38414Smckusick 	splx(s);
156*38414Smckusick 	if (dontroute)
157*38414Smckusick 		so->so_options &= ~SO_DONTROUTE;
158*38414Smckusick 	top = (struct mbuf *)0;
159*38414Smckusick 
160*38414Smckusick release:
161*38414Smckusick 	sbunlock(&so->so_snd);
162*38414Smckusick 	if (top)
163*38414Smckusick 		m_freem(top);
164*38414Smckusick 	return (error);
165*38414Smckusick }
166*38414Smckusick 
167*38414Smckusick /*
168*38414Smckusick  * This is a stripped down udp specific version of soreceive()
169*38414Smckusick  */
170*38414Smckusick nfs_udpreceive(so, aname, mp)
171*38414Smckusick 	register struct socket *so;
172*38414Smckusick 	struct mbuf **aname;
173*38414Smckusick 	struct mbuf **mp;
174*38414Smckusick {
175*38414Smckusick 	register struct mbuf *m;
176*38414Smckusick 	int s, error = 0;
177*38414Smckusick 	struct protosw *pr = so->so_proto;
178*38414Smckusick 	struct mbuf *nextrecord;
179*38414Smckusick 
180*38414Smckusick 	if (aname)
181*38414Smckusick 		*aname = 0;
182*38414Smckusick 
183*38414Smckusick restart:
184*38414Smckusick 	sblock(&so->so_rcv);
185*38414Smckusick 	s = splnet();
186*38414Smckusick 
187*38414Smckusick 	if (so->so_rcv.sb_cc == 0) {
188*38414Smckusick 		if (so->so_error) {
189*38414Smckusick 			error = so->so_error;
190*38414Smckusick 			so->so_error = 0;
191*38414Smckusick 			goto release;
192*38414Smckusick 		}
193*38414Smckusick 		if (so->so_state & SS_CANTRCVMORE)
194*38414Smckusick 			goto release;
195*38414Smckusick 		sbunlock(&so->so_rcv);
196*38414Smckusick 		sbwait(&so->so_rcv);
197*38414Smckusick 		splx(s);
198*38414Smckusick 		goto restart;
199*38414Smckusick 	}
200*38414Smckusick 	m = so->so_rcv.sb_mb;
201*38414Smckusick 	if (m == 0)
202*38414Smckusick 		panic("nfs_receive 1");
203*38414Smckusick 	nextrecord = m->m_nextpkt;
204*38414Smckusick 	if (m->m_type != MT_SONAME)
205*38414Smckusick 		panic("nfs_receive 1a");
206*38414Smckusick 	sbfree(&so->so_rcv, m);
207*38414Smckusick 	if (aname) {
208*38414Smckusick 		*aname = m;
209*38414Smckusick 		so->so_rcv.sb_mb = m->m_next;
210*38414Smckusick 		m->m_next = 0;
211*38414Smckusick 		m = so->so_rcv.sb_mb;
212*38414Smckusick 	} else {
213*38414Smckusick 		MFREE(m, so->so_rcv.sb_mb);
214*38414Smckusick 		m = so->so_rcv.sb_mb;
215*38414Smckusick 	}
216*38414Smckusick 	if (m && m->m_type == MT_RIGHTS)
217*38414Smckusick 		panic("nfs_receive 2");
218*38414Smckusick 	if (m && m->m_type == MT_CONTROL) {
219*38414Smckusick 		sbfree(&so->so_rcv, m);
220*38414Smckusick 		MFREE(m, so->so_rcv.sb_mb);
221*38414Smckusick 		m = so->so_rcv.sb_mb;
222*38414Smckusick 	}
223*38414Smckusick 	*mp = m;
224*38414Smckusick 	while (m) {
225*38414Smckusick 		if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
226*38414Smckusick 			panic("nfs_receive 3");
227*38414Smckusick 		sbfree(&so->so_rcv, m);
228*38414Smckusick 		m = so->so_rcv.sb_mb = m->m_next;
229*38414Smckusick 	}
230*38414Smckusick 	so->so_rcv.sb_mb = nextrecord;
231*38414Smckusick 	so->so_state &= ~SS_RCVATMARK;	/* Necessary ?? */
232*38414Smckusick release:
233*38414Smckusick 	sbunlock(&so->so_rcv);
234*38414Smckusick 	splx(s);
235*38414Smckusick 	return (error);
236*38414Smckusick }
237*38414Smckusick 
238*38414Smckusick struct nfsreq nfsreqh = {
239*38414Smckusick 	(struct nfsreq *)0,
240*38414Smckusick 	(struct nfsreq *)0,
241*38414Smckusick 	(struct mbuf *)0,
242*38414Smckusick 	(struct mbuf *)0,
243*38414Smckusick 	(struct nfsmount *)0,
244*38414Smckusick 	0, 0, 0, 0, 0,
245*38414Smckusick };
246*38414Smckusick 
247*38414Smckusick struct rpc_replyhead {
248*38414Smckusick 	u_long	r_xid;
249*38414Smckusick 	u_long	r_rep;
250*38414Smckusick };
251*38414Smckusick 
252*38414Smckusick /*
253*38414Smckusick  * Implement receipt of reply on a socket.
254*38414Smckusick  * We depend on the way that records are added to the sockbuf
255*38414Smckusick  * by sbappend*.  In particular, each record (mbufs linked through m_next)
256*38414Smckusick  * must begin with an address, followed by optional MT_CONTROL mbuf
257*38414Smckusick  * and then zero or more mbufs of data.
258*38414Smckusick  * Although the sockbuf is locked, new data may still be appended,
259*38414Smckusick  * and thus we must maintain consistency of the sockbuf during that time.
260*38414Smckusick  * We must search through the list of received datagrams matching them
261*38414Smckusick  * with outstanding requests using the xid, until ours is found.
262*38414Smckusick  */
263*38414Smckusick nfs_udpreply(so, mntp, repl, myrep)
264*38414Smckusick 	register struct socket *so;
265*38414Smckusick 	struct nfsmount *mntp;
266*38414Smckusick 	struct nfsreq *repl, *myrep;
267*38414Smckusick {
268*38414Smckusick 	register struct mbuf *m;
269*38414Smckusick 	register struct nfsreq *rep;
270*38414Smckusick 	register int error = 0, s;
271*38414Smckusick 	struct protosw *pr = so->so_proto;
272*38414Smckusick 	struct mbuf *nextrecord;
273*38414Smckusick 	struct sockaddr_in *sad, *sad2;
274*38414Smckusick 	struct rpc_replyhead replyh;
275*38414Smckusick 	struct mbuf *mp;
276*38414Smckusick 	char *cp;
277*38414Smckusick 	int cnt, xfer;
278*38414Smckusick 	int found;
279*38414Smckusick 
280*38414Smckusick restart:
281*38414Smckusick 	/* Already received, bye bye */
282*38414Smckusick 	if (myrep->r_mrep != NULL)
283*38414Smckusick 		return (0);
284*38414Smckusick 	/* If a soft mount and we have run out of retries */
285*38414Smckusick 	if (myrep->r_retry == 0 && myrep->r_timer == 0)
286*38414Smckusick 		return (ETIMEDOUT);
287*38414Smckusick 	nfs_sblock(&so->so_rcv);
288*38414Smckusick 	s = splnet();
289*38414Smckusick 
290*38414Smckusick 	if (so->so_rcv.sb_cc == 0) {
291*38414Smckusick 		if (so->so_error) {
292*38414Smckusick 			error = so->so_error;
293*38414Smckusick 			so->so_error = 0;
294*38414Smckusick 			goto release;
295*38414Smckusick 		}
296*38414Smckusick 		if (so->so_state & SS_CANTRCVMORE)
297*38414Smckusick 			goto release;
298*38414Smckusick 		sbunlock(&so->so_rcv);
299*38414Smckusick 		nfs_sbwait(&so->so_rcv);
300*38414Smckusick 		splx(s);
301*38414Smckusick 		goto restart;
302*38414Smckusick 	}
303*38414Smckusick 	m = so->so_rcv.sb_mb;
304*38414Smckusick 	if (m == 0)
305*38414Smckusick 		panic("nfs_soreply 1");
306*38414Smckusick 	nextrecord = m->m_nextpkt;
307*38414Smckusick 
308*38414Smckusick 	/*
309*38414Smckusick 	 * Take off the address, check for rights and ditch any control
310*38414Smckusick 	 * mbufs.
311*38414Smckusick 	 */
312*38414Smckusick 	if (m->m_type != MT_SONAME)
313*38414Smckusick 		panic("nfs reply SONAME");
314*38414Smckusick 	sad = mtod(m, struct sockaddr_in *);
315*38414Smckusick 	sad2 = mtod(mntp->nm_sockaddr, struct sockaddr_in *);
316*38414Smckusick 	found = 0;
317*38414Smckusick 	if (sad->sin_addr.s_addr != sad2->sin_addr.s_addr)
318*38414Smckusick 		goto dropit;
319*38414Smckusick 	sbfree(&so->so_rcv, m);
320*38414Smckusick 	MFREE(m, so->so_rcv.sb_mb);
321*38414Smckusick 	m = so->so_rcv.sb_mb;
322*38414Smckusick 	if (m && m->m_type == MT_RIGHTS)
323*38414Smckusick 		panic("nfs reply RIGHTS");
324*38414Smckusick 	if (m && m->m_type == MT_CONTROL) {
325*38414Smckusick 		sbfree(&so->so_rcv, m);
326*38414Smckusick 		MFREE(m, so->so_rcv.sb_mb);
327*38414Smckusick 		m = so->so_rcv.sb_mb;
328*38414Smckusick 	}
329*38414Smckusick 	if (m)
330*38414Smckusick 		m->m_nextpkt = nextrecord;
331*38414Smckusick 	else {
332*38414Smckusick 		sbunlock(&so->so_rcv);
333*38414Smckusick 		splx(s);
334*38414Smckusick 		goto restart;
335*38414Smckusick 	}
336*38414Smckusick 
337*38414Smckusick 	/*
338*38414Smckusick 	 * Get the xid and check that it is an rpc reply
339*38414Smckusick 	 */
340*38414Smckusick 	mp = m;
341*38414Smckusick 	if (m->m_len >= 2*NFSX_UNSIGNED)
342*38414Smckusick 		bcopy(mtod(m, caddr_t), (caddr_t)&replyh, 2*NFSX_UNSIGNED);
343*38414Smckusick 	else {
344*38414Smckusick 		cnt = 2*NFSX_UNSIGNED;
345*38414Smckusick 		cp = (caddr_t)&replyh;
346*38414Smckusick 		while (mp && cnt > 0) {
347*38414Smckusick 			if (mp->m_len > 0) {
348*38414Smckusick 				xfer = (mp->m_len >= cnt) ? cnt : mp->m_len;
349*38414Smckusick 				bcopy(mtod(mp, caddr_t), cp, xfer);
350*38414Smckusick 				cnt -= xfer;
351*38414Smckusick 				cp += xfer;
352*38414Smckusick 			}
353*38414Smckusick 			if (cnt > 0)
354*38414Smckusick 				mp = mp->m_next;
355*38414Smckusick 		}
356*38414Smckusick 	}
357*38414Smckusick 	if (replyh.r_rep != rpc_reply || mp == NULL)
358*38414Smckusick 		goto dropit;
359*38414Smckusick 	/*
360*38414Smckusick 	 * Loop through the request list to match up the reply
361*38414Smckusick 	 * Iff no match, just drop the datagram
362*38414Smckusick 	 */
363*38414Smckusick 	rep = repl;
364*38414Smckusick 	while (!found && rep) {
365*38414Smckusick 		if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid) {
366*38414Smckusick 			/* Found it.. */
367*38414Smckusick 			rep->r_mrep = m;
368*38414Smckusick 			while (m) {
369*38414Smckusick 				if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
370*38414Smckusick 					panic("nfs_soreply 3");
371*38414Smckusick 				sbfree(&so->so_rcv, m);
372*38414Smckusick 				m = so->so_rcv.sb_mb = m->m_next;
373*38414Smckusick 			}
374*38414Smckusick 			so->so_rcv.sb_mb = nextrecord;
375*38414Smckusick 			if (rep == myrep)
376*38414Smckusick 				goto release;
377*38414Smckusick 			found++;
378*38414Smckusick 		}
379*38414Smckusick 		rep = rep->r_next;
380*38414Smckusick 	}
381*38414Smckusick 	/* Iff not matched to request, drop it */
382*38414Smckusick dropit:
383*38414Smckusick 	if (!found)
384*38414Smckusick 		sbdroprecord(&so->so_rcv);
385*38414Smckusick 	sbunlock(&so->so_rcv);
386*38414Smckusick 	splx(s);
387*38414Smckusick 	goto restart;
388*38414Smckusick release:
389*38414Smckusick 	sbunlock(&so->so_rcv);
390*38414Smckusick 	splx(s);
391*38414Smckusick 	return (error);
392*38414Smckusick }
393*38414Smckusick 
394*38414Smckusick /*
395*38414Smckusick  * nfs_request - goes something like this
396*38414Smckusick  *	- fill in request struct
397*38414Smckusick  *	- links it into list
398*38414Smckusick  *	- calls nfs_sosend() for first transmit
399*38414Smckusick  *	- calls nfs_soreceive() to get reply
400*38414Smckusick  *	- break down rpc header and return with nfs reply pointed to
401*38414Smckusick  *	  by mrep or error
402*38414Smckusick  * nb: always frees up mreq mbuf list
403*38414Smckusick  */
404*38414Smckusick nfs_request(vp, mreq, xid, mp, mrp, mdp, dposp)
405*38414Smckusick 	struct vnode *vp;
406*38414Smckusick 	struct mbuf *mreq;
407*38414Smckusick 	u_long xid;
408*38414Smckusick 	struct mount *mp;
409*38414Smckusick 	struct mbuf **mrp;
410*38414Smckusick 	struct mbuf **mdp;
411*38414Smckusick 	caddr_t *dposp;
412*38414Smckusick {
413*38414Smckusick 	register struct mbuf *m, *mrep;
414*38414Smckusick 	register struct nfsreq *rep;
415*38414Smckusick 	register u_long *p;
416*38414Smckusick 	register int len;
417*38414Smckusick 	struct nfsmount *mntp;
418*38414Smckusick 	struct mbuf *md;
419*38414Smckusick 	caddr_t dpos;
420*38414Smckusick 	char *cp2;
421*38414Smckusick 	int t1;
422*38414Smckusick 	int s;
423*38414Smckusick 	int error;
424*38414Smckusick 
425*38414Smckusick 	mntp = vfs_to_nfs(mp);
426*38414Smckusick 	m = mreq;
427*38414Smckusick 	MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
428*38414Smckusick 	rep->r_xid = xid;
429*38414Smckusick 	rep->r_mntp = mntp;
430*38414Smckusick 	rep->r_vp = vp;
431*38414Smckusick 	if (mntp->nm_flag & NFSMNT_SOFT)
432*38414Smckusick 		rep->r_retry = mntp->nm_retrans;
433*38414Smckusick 	else
434*38414Smckusick 		rep->r_retry = VNOVAL;
435*38414Smckusick 	rep->r_mrep = NULL;
436*38414Smckusick 	rep->r_mreq = m;
437*38414Smckusick 	rep->r_timer = rep->r_timeout = mntp->nm_timeo;
438*38414Smckusick 	len = 0;
439*38414Smckusick 	while (m) {
440*38414Smckusick 		len += m->m_len;
441*38414Smckusick 		m = m->m_next;
442*38414Smckusick 	}
443*38414Smckusick 	rep->r_msiz = len;
444*38414Smckusick 	m = NFSMCOPY(mreq, 0, M_COPYALL, M_WAIT);
445*38414Smckusick 
446*38414Smckusick 	/* Chain it into list of outstanding requests */
447*38414Smckusick 	s = splnet();
448*38414Smckusick 	rep->r_next = nfsreqh.r_next;
449*38414Smckusick 	if (rep->r_next != NULL)
450*38414Smckusick 		rep->r_next->r_prev = rep;
451*38414Smckusick 	nfsreqh.r_next = rep;
452*38414Smckusick 	rep->r_prev = &nfsreqh;
453*38414Smckusick 	splx(s);
454*38414Smckusick 
455*38414Smckusick 	/*
456*38414Smckusick 	 * Iff the NFSMCOPY above succeeded, send it off...
457*38414Smckusick 	 * otherwise the timer will retransmit later
458*38414Smckusick 	 */
459*38414Smckusick 	if (m != NULL)
460*38414Smckusick 		error = nfs_udpsend(mntp->nm_so, (struct mbuf *)0, m, 0, len);
461*38414Smckusick 	error = nfs_udpreply(mntp->nm_so, mntp, nfsreqh.r_next, rep);
462*38414Smckusick 
463*38414Smckusick 	s = splnet();
464*38414Smckusick 	rep->r_prev->r_next = rep->r_next;
465*38414Smckusick 	if (rep->r_next != NULL)
466*38414Smckusick 		rep->r_next->r_prev = rep->r_prev;
467*38414Smckusick 	splx(s);
468*38414Smckusick 	m_freem(rep->r_mreq);
469*38414Smckusick 	mrep = md = rep->r_mrep;
470*38414Smckusick 	FREE((caddr_t)rep, M_NFSREQ);
471*38414Smckusick 	if (error)
472*38414Smckusick 		return (error);
473*38414Smckusick 
474*38414Smckusick 	/*
475*38414Smckusick 	 * break down the rpc header and check if ok
476*38414Smckusick 	 */
477*38414Smckusick 	dpos = mtod(md, caddr_t);
478*38414Smckusick 	nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED);
479*38414Smckusick 	p += 2;
480*38414Smckusick 	if (*p++ == rpc_msgdenied) {
481*38414Smckusick 		if (*p == rpc_mismatch)
482*38414Smckusick 			error = EOPNOTSUPP;
483*38414Smckusick 		else
484*38414Smckusick 			error = EACCES;
485*38414Smckusick 		m_freem(mrep);
486*38414Smckusick 		return (error);
487*38414Smckusick 	}
488*38414Smckusick 	/*
489*38414Smckusick 	 * skip over the auth_verf, someday we may want to cache auth_short's
490*38414Smckusick 	 * for nfs_reqhead(), but for now just dump it
491*38414Smckusick 	 */
492*38414Smckusick 	if (*++p != 0) {
493*38414Smckusick 		len = nfsm_rndup(fxdr_unsigned(long, *p));
494*38414Smckusick 		nfsm_adv(len);
495*38414Smckusick 	}
496*38414Smckusick 	nfsm_disect(p, u_long *, NFSX_UNSIGNED);
497*38414Smckusick 	/* 0 == ok */
498*38414Smckusick 	if (*p == 0) {
499*38414Smckusick 		nfsm_disect(p, u_long *, NFSX_UNSIGNED);
500*38414Smckusick 		if (*p != 0) {
501*38414Smckusick 			error = fxdr_unsigned(int, *p);
502*38414Smckusick 			m_freem(mrep);
503*38414Smckusick 			return (error);
504*38414Smckusick 		}
505*38414Smckusick 		*mrp = mrep;
506*38414Smckusick 		*mdp = md;
507*38414Smckusick 		*dposp = dpos;
508*38414Smckusick 		return (0);
509*38414Smckusick 	}
510*38414Smckusick 	m_freem(mrep);
511*38414Smckusick 	return (EPROTONOSUPPORT);
512*38414Smckusick nfsmout:
513*38414Smckusick 	return (error);
514*38414Smckusick }
515*38414Smckusick 
516*38414Smckusick /*
517*38414Smckusick  * Get a request for the server main loop
518*38414Smckusick  * - receive a request via. nfs_soreceive()
519*38414Smckusick  * - verify it
520*38414Smckusick  * - fill in the cred struct.
521*38414Smckusick  */
522*38414Smckusick nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, proc, cr)
523*38414Smckusick 	struct socket *so;
524*38414Smckusick 	u_long prog;
525*38414Smckusick 	u_long vers;
526*38414Smckusick 	int maxproc;
527*38414Smckusick 	struct mbuf **nam;
528*38414Smckusick 	struct mbuf **mrp;
529*38414Smckusick 	struct mbuf **mdp;
530*38414Smckusick 	caddr_t *dposp;
531*38414Smckusick 	u_long *retxid;
532*38414Smckusick 	u_long *proc;
533*38414Smckusick 	register struct ucred *cr;
534*38414Smckusick {
535*38414Smckusick 	register int i;
536*38414Smckusick 	register struct mbuf *m;
537*38414Smckusick 	nfsm_vars;
538*38414Smckusick 	int len, len2;
539*38414Smckusick 
540*38414Smckusick 	if (error = nfs_udpreceive(so, nam, &mrep))
541*38414Smckusick 		return (error);
542*38414Smckusick 	md = mrep;
543*38414Smckusick 	dpos = mtod(mrep, caddr_t);
544*38414Smckusick 	nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED);
545*38414Smckusick 	*retxid = *p++;
546*38414Smckusick 	if (*p++ != rpc_call) {
547*38414Smckusick 		m_freem(mrep);
548*38414Smckusick 		return (ERPCMISMATCH);
549*38414Smckusick 	}
550*38414Smckusick 	if (*p++ != rpc_vers) {
551*38414Smckusick 		m_freem(mrep);
552*38414Smckusick 		return (ERPCMISMATCH);
553*38414Smckusick 	}
554*38414Smckusick 	if (*p++ != prog) {
555*38414Smckusick 		m_freem(mrep);
556*38414Smckusick 		return (EPROGUNAVAIL);
557*38414Smckusick 	}
558*38414Smckusick 	if (*p++ != vers) {
559*38414Smckusick 		m_freem(mrep);
560*38414Smckusick 		return (EPROGMISMATCH);
561*38414Smckusick 	}
562*38414Smckusick 	*proc = fxdr_unsigned(u_long, *p++);
563*38414Smckusick 	if (*proc == NFSPROC_NULL) {
564*38414Smckusick 		*mrp = mrep;
565*38414Smckusick 		return (0);
566*38414Smckusick 	}
567*38414Smckusick 	if (*proc > maxproc || *p++ != rpc_auth_unix) {
568*38414Smckusick 		m_freem(mrep);
569*38414Smckusick 		return (EPROCUNAVAIL);
570*38414Smckusick 	}
571*38414Smckusick 	len = fxdr_unsigned(int, *p++);
572*38414Smckusick 	len2 = fxdr_unsigned(int, *++p);
573*38414Smckusick 	nfsm_adv(nfsm_rndup(len2));
574*38414Smckusick 	nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED);
575*38414Smckusick 	cr->cr_uid = fxdr_unsigned(uid_t, *p++);
576*38414Smckusick 	cr->cr_gid = fxdr_unsigned(gid_t, *p++);
577*38414Smckusick 	len2 = fxdr_unsigned(int, *p);
578*38414Smckusick 	if (len2 > 10) {
579*38414Smckusick 		m_freem(mrep);
580*38414Smckusick 		return (EBADRPC);
581*38414Smckusick 	}
582*38414Smckusick 	nfsm_disect(p, u_long *, (len2+2)*NFSX_UNSIGNED);
583*38414Smckusick 	for (i = 1; i <= len2; i++)
584*38414Smckusick 		cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++);
585*38414Smckusick 	cr->cr_ngroups = len2+1;
586*38414Smckusick 	/*
587*38414Smckusick 	 * Do we have any use for the verifier.
588*38414Smckusick 	 * According to the "Remote Procedure Call Protocol Spec." it
589*38414Smckusick 	 * should be AUTH_NULL, but some clients make it AUTH_UNIX?
590*38414Smckusick 	 * For now, just skip over it
591*38414Smckusick 	 */
592*38414Smckusick 	len2 = fxdr_unsigned(int, *++p);
593*38414Smckusick 	if (len2 > 0)
594*38414Smckusick 		nfsm_adv(nfsm_rndup(len2));
595*38414Smckusick 	*mrp = mrep;
596*38414Smckusick 	*mdp = md;
597*38414Smckusick 	*dposp = dpos;
598*38414Smckusick 	return (0);
599*38414Smckusick nfsmout:
600*38414Smckusick 	return (error);
601*38414Smckusick }
602*38414Smckusick 
603*38414Smckusick /*
604*38414Smckusick  * Generate the rpc reply header
605*38414Smckusick  * siz arg. is used to decide if adding a cluster is worthwhile
606*38414Smckusick  */
607*38414Smckusick nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
608*38414Smckusick 	int siz;
609*38414Smckusick 	u_long retxid;
610*38414Smckusick 	int err;
611*38414Smckusick 	struct mbuf **mrq;
612*38414Smckusick 	struct mbuf **mbp;
613*38414Smckusick 	caddr_t *bposp;
614*38414Smckusick {
615*38414Smckusick 	nfsm_vars;
616*38414Smckusick 
617*38414Smckusick 	NFSMGETHDR(mreq);
618*38414Smckusick 	mb = mreq;
619*38414Smckusick 	if ((siz+RPC_REPLYSIZ) > MHLEN)
620*38414Smckusick 		NFSMCLGET(mreq, M_WAIT);
621*38414Smckusick 	p = mtod(mreq, u_long *);
622*38414Smckusick 	mreq->m_len = 6*NFSX_UNSIGNED;
623*38414Smckusick 	bpos = ((caddr_t)p)+mreq->m_len;
624*38414Smckusick 	*p++ = retxid;
625*38414Smckusick 	*p++ = rpc_reply;
626*38414Smckusick 	if (err == ERPCMISMATCH) {
627*38414Smckusick 		*p++ = rpc_msgdenied;
628*38414Smckusick 		*p++ = rpc_mismatch;
629*38414Smckusick 		*p++ = txdr_unsigned(2);
630*38414Smckusick 		*p = txdr_unsigned(2);
631*38414Smckusick 	} else {
632*38414Smckusick 		*p++ = rpc_msgaccepted;
633*38414Smckusick 		*p++ = 0;
634*38414Smckusick 		*p++ = 0;
635*38414Smckusick 		switch (err) {
636*38414Smckusick 		case EPROGUNAVAIL:
637*38414Smckusick 			*p = txdr_unsigned(RPC_PROGUNAVAIL);
638*38414Smckusick 			break;
639*38414Smckusick 		case EPROGMISMATCH:
640*38414Smckusick 			*p = txdr_unsigned(RPC_PROGMISMATCH);
641*38414Smckusick 			nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
642*38414Smckusick 			*p++ = txdr_unsigned(2);
643*38414Smckusick 			*p = txdr_unsigned(2);	/* someday 3 */
644*38414Smckusick 			break;
645*38414Smckusick 		case EPROCUNAVAIL:
646*38414Smckusick 			*p = txdr_unsigned(RPC_PROCUNAVAIL);
647*38414Smckusick 			break;
648*38414Smckusick 		default:
649*38414Smckusick 			*p = 0;
650*38414Smckusick 			if (err != VNOVAL) {
651*38414Smckusick 				nfsm_build(p, u_long *, NFSX_UNSIGNED);
652*38414Smckusick 				*p = txdr_unsigned(err);
653*38414Smckusick 			}
654*38414Smckusick 			break;
655*38414Smckusick 		};
656*38414Smckusick 	}
657*38414Smckusick 	*mrq = mreq;
658*38414Smckusick 	*mbp = mb;
659*38414Smckusick 	*bposp = bpos;
660*38414Smckusick 	if (err != 0 && err != VNOVAL)
661*38414Smckusick 		nfsstats.srvrpc_errs++;
662*38414Smckusick 	return (0);
663*38414Smckusick }
664*38414Smckusick 
665*38414Smckusick /*
666*38414Smckusick  * Nfs timer routine
667*38414Smckusick  * Scan the nfsreq list and retranmit any requests that have timed out
668*38414Smckusick  * To avoid retransmission attempts on STREAM sockets (in the future) make
669*38414Smckusick  * sure to set the r_retry field to 0.
670*38414Smckusick  */
671*38414Smckusick nfs_timer()
672*38414Smckusick {
673*38414Smckusick 	register struct nfsreq *rep;
674*38414Smckusick 	register struct mbuf *m;
675*38414Smckusick 	register struct socket *so;
676*38414Smckusick 	int s, len;
677*38414Smckusick 
678*38414Smckusick 	s = splnet();
679*38414Smckusick 	rep = nfsreqh.r_next;
680*38414Smckusick 	while (rep != NULL) {
681*38414Smckusick 		if (rep->r_timer > 0)
682*38414Smckusick 			rep->r_timer--;
683*38414Smckusick 		else if (rep->r_mrep == NULL && rep->r_retry > 0) {
684*38414Smckusick 			so = rep->r_mntp->nm_so;
685*38414Smckusick 			if ((so->so_state & SS_CANTSENDMORE) == 0 &&
686*38414Smckusick 			    !so->so_error &&
687*38414Smckusick 			    sbspace(&so->so_snd) >= rep->r_msiz) {
688*38414Smckusick 				m = NFSMCOPY(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT);
689*38414Smckusick 				if (m != NULL) {
690*38414Smckusick 					nfsstats.rpcretries++;
691*38414Smckusick 					rep->r_timer = rep->r_timeout;
692*38414Smckusick 					if (rep->r_retry != VNOVAL)
693*38414Smckusick 						rep->r_retry--;
694*38414Smckusick #ifdef MGETHDR
695*38414Smckusick 					m->m_pkthdr.len = rep->r_msiz;
696*38414Smckusick #endif
697*38414Smckusick 					(*so->so_proto->pr_usrreq)(so, PRU_SEND,
698*38414Smckusick 						m, (caddr_t)0, (struct mbuf *)0,
699*38414Smckusick 						(struct mbuf *)0);
700*38414Smckusick 				}
701*38414Smckusick 			}
702*38414Smckusick 		}
703*38414Smckusick 		rep = rep->r_next;
704*38414Smckusick 	}
705*38414Smckusick 	splx(s);
706*38414Smckusick 	timeout(nfs_timer, (caddr_t)0, hz);
707*38414Smckusick }
708*38414Smckusick 
709*38414Smckusick /*
710*38414Smckusick  * nfs_sbwait() is simply sbwait() but at a negative priority so that it
711*38414Smckusick  * can not be interrupted by a signal.
712*38414Smckusick  */
713*38414Smckusick nfs_sbwait(sb)
714*38414Smckusick 	struct sockbuf *sb;
715*38414Smckusick {
716*38414Smckusick 	sb->sb_flags |= SB_WAIT;
717*38414Smckusick 	sleep((caddr_t)&sb->sb_cc, PZERO-1);
718*38414Smckusick }
719