svc_vc.c revision 269398
1114402Sru/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
2114402Sru
3114402Sru/*-
4114402Sru * Copyright (c) 2009, Sun Microsystems, Inc.
5114402Sru * All rights reserved.
6114402Sru *
7114402Sru * Redistribution and use in source and binary forms, with or without
8114402Sru * modification, are permitted provided that the following conditions are met:
9114402Sru * - Redistributions of source code must retain the above copyright notice,
10114402Sru *   this list of conditions and the following disclaimer.
11114402Sru * - Redistributions in binary form must reproduce the above copyright notice,
12114402Sru *   this list of conditions and the following disclaimer in the documentation
13151497Sru *   and/or other materials provided with the distribution.
14114402Sru * - Neither the name of Sun Microsystems, Inc. nor the names of its
15114402Sru *   contributors may be used to endorse or promote products derived
16114402Sru *   from this software without specific prior written permission.
17114402Sru *
18114402Sru * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19114402Sru * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20114402Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21114402Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22114402Sru * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23114402Sru * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24114402Sru * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25114402Sru * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26114402Sru * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27114402Sru * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28114402Sru * POSSIBILITY OF SUCH DAMAGE.
29151497Sru */
30151497Sru
31114402Sru#if defined(LIBC_SCCS) && !defined(lint)
32114402Srustatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
33114402Srustatic char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
34114402Sru#endif
35114402Sru#include <sys/cdefs.h>
36114402Sru__FBSDID("$FreeBSD: stable/10/sys/rpc/svc_vc.c 269398 2014-08-01 21:10:41Z rmacklem $");
37114402Sru
38114402Sru/*
39114402Sru * svc_vc.c, Server side for Connection Oriented based RPC.
40114402Sru *
41114402Sru * Actually implements two flavors of transporter -
42114402Sru * a tcp rendezvouser (a listner and connection establisher)
43114402Sru * and a record/tcp stream.
44114402Sru */
45151497Sru
46151497Sru#include <sys/param.h>
47151497Sru#include <sys/lock.h>
48151497Sru#include <sys/kernel.h>
4975584Sru#include <sys/malloc.h>
5075584Sru#include <sys/mbuf.h>
51104862Sru#include <sys/mutex.h>
52151497Sru#include <sys/proc.h>
5375584Sru#include <sys/protosw.h>
54104862Sru#include <sys/queue.h>
55104862Sru#include <sys/socket.h>
56104862Sru#include <sys/socketvar.h>
57104862Sru#include <sys/sx.h>
58104862Sru#include <sys/systm.h>
59104862Sru#include <sys/uio.h>
60104862Sru
61104862Sru#include <net/vnet.h>
62104862Sru
63104862Sru#include <netinet/tcp.h>
64104862Sru
65104862Sru#include <rpc/rpc.h>
66104862Sru
67104862Sru#include <rpc/krpc.h>
68104862Sru#include <rpc/rpc_com.h>
69104862Sru
70104862Sru#include <security/mac/mac_framework.h>
71104862Sru
72114402Srustatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
73114402Sru    struct sockaddr **, struct mbuf **);
74114402Srustatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
75114402Srustatic void svc_vc_rendezvous_destroy(SVCXPRT *);
76114402Srustatic bool_t svc_vc_null(void);
77114402Srustatic void svc_vc_destroy(SVCXPRT *);
78114402Srustatic enum xprt_stat svc_vc_stat(SVCXPRT *);
79114402Srustatic bool_t svc_vc_ack(SVCXPRT *, uint32_t *);
80114402Srustatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
81114402Sru    struct sockaddr **, struct mbuf **);
82114402Srustatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
83114402Sru    struct sockaddr *, struct mbuf *, uint32_t *seq);
84114402Srustatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
85114402Srustatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
86114402Sru    void *in);
87114402Srustatic void svc_vc_backchannel_destroy(SVCXPRT *);
88114402Srustatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
89114402Srustatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
90114402Sru    struct sockaddr **, struct mbuf **);
91114402Srustatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
92114402Sru    struct sockaddr *, struct mbuf *, uint32_t *);
93114402Srustatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
94114402Sru    void *in);
95114402Srustatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
96114402Sru    struct sockaddr *raddr);
97114402Srustatic int svc_vc_accept(struct socket *head, struct socket **sop);
98114402Srustatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
99114402Sru
100114402Srustatic struct xp_ops svc_vc_rendezvous_ops = {
101114402Sru	.xp_recv =	svc_vc_rendezvous_recv,
102114402Sru	.xp_stat =	svc_vc_rendezvous_stat,
103114402Sru	.xp_reply =	(bool_t (*)(SVCXPRT *, struct rpc_msg *,
104114402Sru		struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null,
105114402Sru	.xp_destroy =	svc_vc_rendezvous_destroy,
106114402Sru	.xp_control =	svc_vc_rendezvous_control
107114402Sru};
108114402Sru
109114402Srustatic struct xp_ops svc_vc_ops = {
110114402Sru	.xp_recv =	svc_vc_recv,
111114402Sru	.xp_stat =	svc_vc_stat,
112151497Sru	.xp_ack =	svc_vc_ack,
113151497Sru	.xp_reply =	svc_vc_reply,
114151497Sru	.xp_destroy =	svc_vc_destroy,
115151497Sru	.xp_control =	svc_vc_control
116151497Sru};
117151497Sru
118151497Srustatic struct xp_ops svc_vc_backchannel_ops = {
119151497Sru	.xp_recv =	svc_vc_backchannel_recv,
120151497Sru	.xp_stat =	svc_vc_backchannel_stat,
121151497Sru	.xp_reply =	svc_vc_backchannel_reply,
122151497Sru	.xp_destroy =	svc_vc_backchannel_destroy,
123151497Sru	.xp_control =	svc_vc_backchannel_control
124114402Sru};
125114402Sru
126114402Sru/*
127114402Sru * Usage:
128104862Sru *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
129104862Sru *
130104862Sru * Creates, registers, and returns a (rpc) tcp based transporter.
131114402Sru * Once *xprt is initialized, it is registered as a transporter
132114402Sru * see (svc.h, xprt_register).  This routine returns
133114402Sru * a NULL if a problem occurred.
134114402Sru *
13575584Sru * The filedescriptor passed in is expected to refer to a bound, but
136114402Sru * not yet connected socket.
137114402Sru *
138114402Sru * Since streams do buffered io similar to stdio, the caller can specify
139114402Sru * how big the send and receive buffers are via the second and third parms;
140114402Sru * 0 => use the system default.
141114402Sru */
142114402SruSVCXPRT *
143114402Srusvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
144114402Sru    size_t recvsize)
145114402Sru{
146114402Sru	SVCXPRT *xprt;
147114402Sru	struct sockaddr* sa;
148114402Sru	int error;
149114402Sru
150114402Sru	SOCK_LOCK(so);
151114402Sru	if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) {
152114402Sru		SOCK_UNLOCK(so);
153114402Sru		error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
154114402Sru		if (error)
155114402Sru			return (NULL);
156114402Sru		xprt = svc_vc_create_conn(pool, so, sa);
157114402Sru		free(sa, M_SONAME);
158114402Sru		return (xprt);
159114402Sru	}
160114402Sru	SOCK_UNLOCK(so);
161114402Sru
162114402Sru	xprt = svc_xprt_alloc();
163114402Sru	sx_init(&xprt->xp_lock, "xprt->xp_lock");
164114402Sru	xprt->xp_pool = pool;
165114402Sru	xprt->xp_socket = so;
166114402Sru	xprt->xp_p1 = NULL;
167114402Sru	xprt->xp_p2 = NULL;
168114402Sru	xprt->xp_ops = &svc_vc_rendezvous_ops;
169114402Sru
170114402Sru	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
171114402Sru	if (error) {
172114402Sru		goto cleanup_svc_vc_create;
173114402Sru	}
174114402Sru
175114402Sru	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
176114402Sru	free(sa, M_SONAME);
177114402Sru
178114402Sru	xprt_register(xprt);
179114402Sru
180114402Sru	solisten(so, SOMAXCONN, curthread);
181114402Sru
182114402Sru	SOCKBUF_LOCK(&so->so_rcv);
183114402Sru	xprt->xp_upcallset = 1;
184114402Sru	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
185114402Sru	SOCKBUF_UNLOCK(&so->so_rcv);
186114402Sru
187114402Sru	return (xprt);
188114402Srucleanup_svc_vc_create:
189114402Sru	if (xprt) {
190114402Sru		sx_destroy(&xprt->xp_lock);
191114402Sru		svc_xprt_free(xprt);
192114402Sru	}
193114402Sru	return (NULL);
194114402Sru}
195114402Sru
196114402Sru/*
197114402Sru * Create a new transport for a socket optained via soaccept().
198114402Sru */
199114402SruSVCXPRT *
200114402Srusvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
201114402Sru{
202114402Sru	SVCXPRT *xprt = NULL;
203114402Sru	struct cf_conn *cd = NULL;
204114402Sru	struct sockaddr* sa = NULL;
205114402Sru	struct sockopt opt;
206114402Sru	int one = 1;
207114402Sru	int error;
208114402Sru
209114402Sru	bzero(&opt, sizeof(struct sockopt));
210114402Sru	opt.sopt_dir = SOPT_SET;
211151497Sru	opt.sopt_level = SOL_SOCKET;
212114402Sru	opt.sopt_name = SO_KEEPALIVE;
213114402Sru	opt.sopt_val = &one;
214114402Sru	opt.sopt_valsize = sizeof(one);
215114402Sru	error = sosetopt(so, &opt);
216114402Sru	if (error) {
217114402Sru		return (NULL);
218114402Sru	}
219114402Sru
220114402Sru	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
221114402Sru		bzero(&opt, sizeof(struct sockopt));
222114402Sru		opt.sopt_dir = SOPT_SET;
223114402Sru		opt.sopt_level = IPPROTO_TCP;
224114402Sru		opt.sopt_name = TCP_NODELAY;
225114402Sru		opt.sopt_val = &one;
226114402Sru		opt.sopt_valsize = sizeof(one);
227114402Sru		error = sosetopt(so, &opt);
228114402Sru		if (error) {
229114402Sru			return (NULL);
230114402Sru		}
231114402Sru	}
232114402Sru
233114402Sru	cd = mem_alloc(sizeof(*cd));
234114402Sru	cd->strm_stat = XPRT_IDLE;
235114402Sru
236114402Sru	xprt = svc_xprt_alloc();
237114402Sru	sx_init(&xprt->xp_lock, "xprt->xp_lock");
238114402Sru	xprt->xp_pool = pool;
239114402Sru	xprt->xp_socket = so;
240114402Sru	xprt->xp_p1 = cd;
241114402Sru	xprt->xp_p2 = NULL;
242114402Sru	xprt->xp_ops = &svc_vc_ops;
243114402Sru
244114402Sru	/*
245114402Sru	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
246114402Sru	 * has a 5 minute timer, server has a 6 minute timer.
247114402Sru	 */
248114402Sru	xprt->xp_idletimeout = 6 * 60;
249114402Sru
250114402Sru	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
251114402Sru
252114402Sru	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
253114402Sru	if (error)
254114402Sru		goto cleanup_svc_vc_create;
255114402Sru
256114402Sru	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
257114402Sru	free(sa, M_SONAME);
258114402Sru
259114402Sru	xprt_register(xprt);
260114402Sru
261114402Sru	SOCKBUF_LOCK(&so->so_rcv);
262114402Sru	xprt->xp_upcallset = 1;
263114402Sru	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
264151497Sru	SOCKBUF_UNLOCK(&so->so_rcv);
265114402Sru
266104862Sru	/*
26775584Sru	 * Throw the transport into the active list in case it already
26875584Sru	 * has some data buffered.
26975584Sru	 */
270151497Sru	sx_xlock(&xprt->xp_lock);
271151497Sru	xprt_active(xprt);
272151497Sru	sx_xunlock(&xprt->xp_lock);
273151497Sru
274151497Sru	return (xprt);
275151497Srucleanup_svc_vc_create:
276151497Sru	if (xprt) {
277104862Sru		sx_destroy(&xprt->xp_lock);
27875584Sru		svc_xprt_free(xprt);
27975584Sru	}
280104862Sru	if (cd)
281104862Sru		mem_free(cd, sizeof(*cd));
282104862Sru	return (NULL);
283104862Sru}
284151497Sru
28575584Sru/*
286151497Sru * Create a new transport for a backchannel on a clnt_vc socket.
287151497Sru */
288151497SruSVCXPRT *
289151497Srusvc_vc_create_backchannel(SVCPOOL *pool)
290151497Sru{
291151497Sru	SVCXPRT *xprt = NULL;
292151497Sru	struct cf_conn *cd = NULL;
293151497Sru
294151497Sru	cd = mem_alloc(sizeof(*cd));
295114402Sru	cd->strm_stat = XPRT_IDLE;
296104862Sru
29775584Sru	xprt = svc_xprt_alloc();
298104862Sru	sx_init(&xprt->xp_lock, "xprt->xp_lock");
299104862Sru	xprt->xp_pool = pool;
300104862Sru	xprt->xp_socket = NULL;
301114402Sru	xprt->xp_p1 = cd;
302114402Sru	xprt->xp_p2 = NULL;
303104862Sru	xprt->xp_ops = &svc_vc_backchannel_ops;
304104862Sru	return (xprt);
305104862Sru}
306104862Sru
307104862Sru/*
308114402Sru * This does all of the accept except the final call to soaccept. The
309104862Sru * caller will call soaccept after dropping its locks (soaccept may
310104862Sru * call malloc).
311104862Sru */
31275584Sruint
31375584Srusvc_vc_accept(struct socket *head, struct socket **sop)
314114402Sru{
315104862Sru	int error = 0;
31675584Sru	struct socket *so;
317104862Sru
31875584Sru	if ((head->so_options & SO_ACCEPTCONN) == 0) {
31975584Sru		error = EINVAL;
320114402Sru		goto done;
321114402Sru	}
322114402Sru#ifdef MAC
32375584Sru	error = mac_socket_check_accept(curthread->td_ucred, head);
32475584Sru	if (error != 0)
325151497Sru		goto done;
326151497Sru#endif
327151497Sru	ACCEPT_LOCK();
328151497Sru	if (TAILQ_EMPTY(&head->so_comp)) {
329114402Sru		ACCEPT_UNLOCK();
330151497Sru		error = EWOULDBLOCK;
331151497Sru		goto done;
332151497Sru	}
333151497Sru	so = TAILQ_FIRST(&head->so_comp);
334114402Sru	KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
335151497Sru	KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
336114402Sru
337151497Sru	/*
338151497Sru	 * Before changing the flags on the socket, we have to bump the
339151497Sru	 * reference count.  Otherwise, if the protocol calls sofree(),
340114402Sru	 * the socket will be released due to a zero refcount.
341114402Sru	 * XXX might not need soref() since this is simpler than kern_accept.
342114402Sru	 */
343151497Sru	SOCK_LOCK(so);			/* soref() and so_state update */
344151497Sru	soref(so);			/* file descriptor reference */
345151497Sru
346151497Sru	TAILQ_REMOVE(&head->so_comp, so, so_list);
347151497Sru	head->so_qlen--;
348151497Sru	so->so_state |= (head->so_state & SS_NBIO);
349151497Sru	so->so_qstate &= ~SQ_COMP;
350151497Sru	so->so_head = NULL;
351151497Sru
352151497Sru	SOCK_UNLOCK(so);
353151497Sru	ACCEPT_UNLOCK();
354151497Sru
355151497Sru	*sop = so;
356151497Sru
357151497Sru	/* connection has been removed from the listen queue */
358151497Sru	KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
359151497Srudone:
360151497Sru	return (error);
361151497Sru}
362151497Sru
363151497Sru/*ARGSUSED*/
364151497Srustatic bool_t
365151497Srusvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
366151497Sru    struct sockaddr **addrp, struct mbuf **mp)
367151497Sru{
368151497Sru	struct socket *so = NULL;
369114402Sru	struct sockaddr *sa = NULL;
370114402Sru	int error;
371114402Sru	SVCXPRT *new_xprt;
372104862Sru
373114402Sru	/*
374104862Sru	 * The socket upcall calls xprt_active() which will eventually
375104862Sru	 * cause the server to call us here. We attempt to accept a
376114402Sru	 * connection from the socket and turn it into a new
377104862Sru	 * transport. If the accept fails, we have drained all pending
378104862Sru	 * connections so we call xprt_inactive().
379114402Sru	 */
380104862Sru	sx_xlock(&xprt->xp_lock);
381104862Sru
382104862Sru	error = svc_vc_accept(xprt->xp_socket, &so);
383104862Sru
384104862Sru	if (error == EWOULDBLOCK) {
385104862Sru		/*
386104862Sru		 * We must re-test for new connections after taking
387104862Sru		 * the lock to protect us in the case where a new
388104862Sru		 * connection arrives after our call to accept fails
389104862Sru		 * with EWOULDBLOCK.
390104862Sru		 */
391104862Sru		ACCEPT_LOCK();
392104862Sru		if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
393104862Sru			xprt_inactive_self(xprt);
394104862Sru		ACCEPT_UNLOCK();
395104862Sru		sx_xunlock(&xprt->xp_lock);
39675584Sru		return (FALSE);
397104862Sru	}
398104862Sru
399104862Sru	if (error) {
400104862Sru		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
40175584Sru		if (xprt->xp_upcallset) {
40275584Sru			xprt->xp_upcallset = 0;
403151497Sru			soupcall_clear(xprt->xp_socket, SO_RCV);
404151497Sru		}
405151497Sru		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
406151497Sru		xprt_inactive_self(xprt);
407151497Sru		sx_xunlock(&xprt->xp_lock);
408151497Sru		return (FALSE);
409151497Sru	}
410151497Sru
411151497Sru	sx_xunlock(&xprt->xp_lock);
412151497Sru
413151497Sru	sa = 0;
414151497Sru	error = soaccept(so, &sa);
415151497Sru
416151497Sru	if (error) {
417151497Sru		/*
418151497Sru		 * XXX not sure if I need to call sofree or soclose here.
419151497Sru		 */
420151497Sru		if (sa)
421151497Sru			free(sa, M_SONAME);
422151497Sru		return (FALSE);
423151497Sru	}
424151497Sru
425151497Sru	/*
426151497Sru	 * svc_vc_create_conn will call xprt_register - we don't need
427151497Sru	 * to do anything with the new connection except derefence it.
428151497Sru	 */
42975584Sru	new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
43075584Sru	if (!new_xprt) {
431114402Sru		soclose(so);
432104862Sru	} else {
433104862Sru		SVC_RELEASE(new_xprt);
434104862Sru	}
435104862Sru
436104862Sru	free(sa, M_SONAME);
437104862Sru
438104862Sru	return (FALSE); /* there is never an rpc msg to be processed */
439114402Sru}
440104862Sru
441104862Sru/*ARGSUSED*/
442104862Srustatic enum xprt_stat
443104862Srusvc_vc_rendezvous_stat(SVCXPRT *xprt)
444104862Sru{
445104862Sru
446104862Sru	return (XPRT_IDLE);
447104862Sru}
448104862Sru
44975584Srustatic void
450104862Srusvc_vc_destroy_common(SVCXPRT *xprt)
451151497Sru{
452104862Sru	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
453104862Sru	if (xprt->xp_upcallset) {
454151497Sru		xprt->xp_upcallset = 0;
455104862Sru		soupcall_clear(xprt->xp_socket, SO_RCV);
456151497Sru	}
457104862Sru	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
458104862Sru
459104862Sru	if (xprt->xp_socket)
460104862Sru		(void)soclose(xprt->xp_socket);
461104862Sru
462104862Sru	if (xprt->xp_netid)
463104862Sru		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
464151497Sru	svc_xprt_free(xprt);
465151497Sru}
46675584Sru
467104862Srustatic void
468104862Srusvc_vc_rendezvous_destroy(SVCXPRT *xprt)
469104862Sru{
470114402Sru
471104862Sru	svc_vc_destroy_common(xprt);
47275584Sru}
473104862Sru
474104862Srustatic void
475104862Srusvc_vc_destroy(SVCXPRT *xprt)
476104862Sru{
477104862Sru	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
478104862Sru
479104862Sru	svc_vc_destroy_common(xprt);
480104862Sru
481104862Sru	if (cd->mreq)
48275584Sru		m_freem(cd->mreq);
483104862Sru	if (cd->mpending)
484151497Sru		m_freem(cd->mpending);
485104862Sru	mem_free(cd, sizeof(*cd));
486104862Sru}
487151497Sru
488104862Srustatic void
489151497Srusvc_vc_backchannel_destroy(SVCXPRT *xprt)
49075584Sru{
491104862Sru	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
492104862Sru	struct mbuf *m, *m2;
493104862Sru
494104862Sru	svc_xprt_free(xprt);
495104862Sru	m = cd->mreq;
496104862Sru	while (m != NULL) {
497104862Sru		m2 = m;
498104862Sru		m = m->m_nextpkt;
499151497Sru		m_freem(m2);
500104862Sru	}
501151497Sru	mem_free(cd, sizeof(*cd));
502104862Sru}
50375584Sru
504104862Sru/*ARGSUSED*/
505151497Srustatic bool_t
506104862Srusvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
507151497Sru{
508151497Sru	return (FALSE);
50975584Sru}
51075584Sru
51175584Srustatic bool_t
512104862Srusvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
513104862Sru{
514114402Sru
515104862Sru	return (FALSE);
516104862Sru}
517104862Sru
518104862Srustatic bool_t
51975584Srusvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
520104862Sru{
521104862Sru
522104862Sru	return (FALSE);
523114402Sru}
524114402Sru
525114402Srustatic enum xprt_stat
526104862Srusvc_vc_stat(SVCXPRT *xprt)
527104862Sru{
528104862Sru	struct cf_conn *cd;
529104862Sru
530104862Sru	cd = (struct cf_conn *)(xprt->xp_p1);
531151497Sru
532104862Sru	if (cd->strm_stat == XPRT_DIED)
533104862Sru		return (XPRT_DIED);
534104862Sru
535104862Sru	if (cd->mreq != NULL && cd->resid == 0 && cd->eor)
536151497Sru		return (XPRT_MOREREQS);
537104862Sru
538151497Sru	if (soreadable(xprt->xp_socket))
539104862Sru		return (XPRT_MOREREQS);
540104862Sru
541104862Sru	return (XPRT_IDLE);
542104862Sru}
543104862Sru
544104862Srustatic bool_t
545104862Srusvc_vc_ack(SVCXPRT *xprt, uint32_t *ack)
546104862Sru{
547104862Sru
54875584Sru	*ack = atomic_load_acq_32(&xprt->xp_snt_cnt);
549104862Sru	*ack -= xprt->xp_socket->so_snd.sb_cc;
550104862Sru	return (TRUE);
551104862Sru}
552104862Sru
553104862Srustatic enum xprt_stat
554104862Srusvc_vc_backchannel_stat(SVCXPRT *xprt)
555104862Sru{
556104862Sru	struct cf_conn *cd;
557104862Sru
558104862Sru	cd = (struct cf_conn *)(xprt->xp_p1);
559104862Sru
560104862Sru	if (cd->mreq != NULL)
561104862Sru		return (XPRT_MOREREQS);
562104862Sru
563104862Sru	return (XPRT_IDLE);
564104862Sru}
565104862Sru
566104862Sru/*
567104862Sru * If we have an mbuf chain in cd->mpending, try to parse a record from it,
568104862Sru * leaving the result in cd->mreq. If we don't have a complete record, leave
569151497Sru * the partial result in cd->mreq and try to read more from the socket.
570104862Sru */
571104862Srustatic int
572104862Srusvc_vc_process_pending(SVCXPRT *xprt)
573151497Sru{
574151497Sru	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
575151497Sru	struct socket *so = xprt->xp_socket;
576151497Sru	struct mbuf *m;
577151497Sru
578151497Sru	/*
579151497Sru	 * If cd->resid is non-zero, we have part of the
580151497Sru	 * record already, otherwise we are expecting a record
581151497Sru	 * marker.
582151497Sru	 */
583151497Sru	if (!cd->resid && cd->mpending) {
584151497Sru		/*
585151497Sru		 * See if there is enough data buffered to
586151497Sru		 * make up a record marker. Make sure we can
587151497Sru		 * handle the case where the record marker is
588151497Sru		 * split across more than one mbuf.
589151497Sru		 */
590151497Sru		size_t n = 0;
591151497Sru		uint32_t header;
592151497Sru
593151497Sru		m = cd->mpending;
594151497Sru		while (n < sizeof(uint32_t) && m) {
595151497Sru			n += m->m_len;
596151497Sru			m = m->m_next;
597151497Sru		}
598151497Sru		if (n < sizeof(uint32_t)) {
599114402Sru			so->so_rcv.sb_lowat = sizeof(uint32_t) - n;
600151497Sru			return (FALSE);
601104862Sru		}
602104862Sru		m_copydata(cd->mpending, 0, sizeof(header),
603104862Sru		    (char *)&header);
604104862Sru		header = ntohl(header);
605151497Sru		cd->eor = (header & 0x80000000) != 0;
606151497Sru		cd->resid = header & 0x7fffffff;
607151497Sru		m_adj(cd->mpending, sizeof(uint32_t));
608151497Sru	}
609151497Sru
610104862Sru	/*
611104862Sru	 * Start pulling off mbufs from cd->mpending
612104862Sru	 * until we either have a complete record or
613104862Sru	 * we run out of data. We use m_split to pull
614104862Sru	 * data - it will pull as much as possible and
615151497Sru	 * split the last mbuf if necessary.
616151497Sru	 */
617151497Sru	while (cd->mpending && cd->resid) {
618104862Sru		m = cd->mpending;
619151497Sru		if (cd->mpending->m_next
620151497Sru		    || cd->mpending->m_len > cd->resid)
621151497Sru			cd->mpending = m_split(cd->mpending,
622151497Sru			    cd->resid, M_WAITOK);
623151497Sru		else
624151497Sru			cd->mpending = NULL;
625151497Sru		if (cd->mreq)
626151497Sru			m_last(cd->mreq)->m_next = m;
627151497Sru		else
628151497Sru			cd->mreq = m;
629151497Sru		while (m) {
630151497Sru			cd->resid -= m->m_len;
631151497Sru			m = m->m_next;
632151497Sru		}
633151497Sru	}
634151497Sru
635151497Sru	/*
636151497Sru	 * Block receive upcalls if we have more data pending,
637151497Sru	 * otherwise report our need.
638151497Sru	 */
639151497Sru	if (cd->mpending)
640151497Sru		so->so_rcv.sb_lowat = INT_MAX;
641104862Sru	else
642151497Sru		so->so_rcv.sb_lowat =
643151497Sru		    imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2));
644151497Sru	return (TRUE);
645151497Sru}
646151497Sru
647151497Srustatic bool_t
648151497Srusvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
649151497Sru    struct sockaddr **addrp, struct mbuf **mp)
650151497Sru{
651151497Sru	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
652151497Sru	struct uio uio;
653151497Sru	struct mbuf *m;
654151497Sru	struct socket* so = xprt->xp_socket;
655151497Sru	XDR xdrs;
656151497Sru	int error, rcvflag;
657151497Sru	uint32_t xid_plus_direction[2];
658151497Sru
659151497Sru	/*
660151497Sru	 * Serialise access to the socket and our own record parsing
661151497Sru	 * state.
662151497Sru	 */
663151497Sru	sx_xlock(&xprt->xp_lock);
664151497Sru
665151497Sru	for (;;) {
666151497Sru		/* If we have no request ready, check pending queue. */
667151497Sru		while (cd->mpending &&
668151497Sru		    (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) {
669151497Sru			if (!svc_vc_process_pending(xprt))
670151497Sru				break;
671151497Sru		}
672151497Sru
673151497Sru		/* Process and return complete request in cd->mreq. */
674151497Sru		if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
675151497Sru
676151497Sru			/*
677151497Sru			 * Now, check for a backchannel reply.
678151497Sru			 * The XID is in the first uint32_t of the reply
679151497Sru			 * and the message direction is the second one.
680151497Sru			 */
681151497Sru			if ((cd->mreq->m_len >= sizeof(xid_plus_direction) ||
682151497Sru			    m_length(cd->mreq, NULL) >=
683151497Sru			    sizeof(xid_plus_direction)) &&
684151497Sru			    xprt->xp_p2 != NULL) {
685151497Sru				m_copydata(cd->mreq, 0,
686151497Sru				    sizeof(xid_plus_direction),
687151497Sru				    (char *)xid_plus_direction);
688151497Sru				xid_plus_direction[0] =
689151497Sru				    ntohl(xid_plus_direction[0]);
690151497Sru				xid_plus_direction[1] =
691151497Sru				    ntohl(xid_plus_direction[1]);
692151497Sru				/* Check message direction. */
693151497Sru				if (xid_plus_direction[1] == REPLY) {
694151497Sru					clnt_bck_svccall(xprt->xp_p2,
695151497Sru					    cd->mreq,
696151497Sru					    xid_plus_direction[0]);
697104862Sru					cd->mreq = NULL;
698151497Sru					continue;
699151497Sru				}
700151497Sru			}
701104862Sru
702151497Sru			xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
703151497Sru			cd->mreq = NULL;
70475584Sru
705104862Sru			/* Check for next request in a pending queue. */
706151497Sru			svc_vc_process_pending(xprt);
707151497Sru			if (cd->mreq == NULL || cd->resid != 0) {
708104862Sru				SOCKBUF_LOCK(&so->so_rcv);
709104862Sru				if (!soreadable(so))
710151497Sru					xprt_inactive_self(xprt);
711151497Sru				SOCKBUF_UNLOCK(&so->so_rcv);
712104862Sru			}
713104862Sru
714104862Sru			sx_xunlock(&xprt->xp_lock);
715104862Sru
716104862Sru			if (! xdr_callmsg(&xdrs, msg)) {
717104862Sru				XDR_DESTROY(&xdrs);
718151497Sru				return (FALSE);
719104862Sru			}
720104862Sru
721151497Sru			*addrp = NULL;
722151497Sru			*mp = xdrmbuf_getall(&xdrs);
723151497Sru			XDR_DESTROY(&xdrs);
724104862Sru
725104862Sru			return (TRUE);
726104862Sru		}
727104862Sru
728104862Sru		/*
729104862Sru		 * The socket upcall calls xprt_active() which will eventually
730104862Sru		 * cause the server to call us here. We attempt to
731104862Sru		 * read as much as possible from the socket and put
732104862Sru		 * the result in cd->mpending. If the read fails,
733104862Sru		 * we have drained both cd->mpending and the socket so
734104862Sru		 * we can call xprt_inactive().
735104862Sru		 */
736104862Sru		uio.uio_resid = 1000000000;
737151497Sru		uio.uio_td = curthread;
738104862Sru		m = NULL;
739104862Sru		rcvflag = MSG_DONTWAIT;
740151497Sru		error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
741151497Sru
742151497Sru		if (error == EWOULDBLOCK) {
743151497Sru			/*
744104862Sru			 * We must re-test for readability after
745104862Sru			 * taking the lock to protect us in the case
746104862Sru			 * where a new packet arrives on the socket
747104862Sru			 * after our call to soreceive fails with
748104862Sru			 * EWOULDBLOCK.
749104862Sru			 */
750104862Sru			SOCKBUF_LOCK(&so->so_rcv);
751104862Sru			if (!soreadable(so))
752104862Sru				xprt_inactive_self(xprt);
75375584Sru			SOCKBUF_UNLOCK(&so->so_rcv);
754114402Sru			sx_xunlock(&xprt->xp_lock);
755104862Sru			return (FALSE);
75675584Sru		}
757104862Sru
758104862Sru		if (error) {
759104862Sru			SOCKBUF_LOCK(&so->so_rcv);
760104862Sru			if (xprt->xp_upcallset) {
761104862Sru				xprt->xp_upcallset = 0;
762104862Sru				soupcall_clear(so, SO_RCV);
763104862Sru			}
764104862Sru			SOCKBUF_UNLOCK(&so->so_rcv);
765104862Sru			xprt_inactive_self(xprt);
766104862Sru			cd->strm_stat = XPRT_DIED;
767104862Sru			sx_xunlock(&xprt->xp_lock);
768104862Sru			return (FALSE);
769104862Sru		}
770104862Sru
771104862Sru		if (!m) {
772104862Sru			/*
773104862Sru			 * EOF - the other end has closed the socket.
774151497Sru			 */
77575584Sru			xprt_inactive_self(xprt);
776104862Sru			cd->strm_stat = XPRT_DIED;
777104862Sru			sx_xunlock(&xprt->xp_lock);
778104862Sru			return (FALSE);
779104862Sru		}
780151497Sru
781104862Sru		if (cd->mpending)
782114402Sru			m_last(cd->mpending)->m_next = m;
783104862Sru		else
78475584Sru			cd->mpending = m;
785104862Sru	}
786104862Sru}
787104862Sru
788104862Srustatic bool_t
789151497Srusvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
790104862Sru    struct sockaddr **addrp, struct mbuf **mp)
791114402Sru{
792104862Sru	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
793104862Sru	struct ct_data *ct;
794151497Sru	struct mbuf *m;
795104862Sru	XDR xdrs;
796104862Sru
797151497Sru	sx_xlock(&xprt->xp_lock);
798104862Sru	ct = (struct ct_data *)xprt->xp_p2;
799114402Sru	if (ct == NULL) {
800104862Sru		sx_xunlock(&xprt->xp_lock);
801104862Sru		return (FALSE);
802104862Sru	}
803104862Sru	mtx_lock(&ct->ct_lock);
804104862Sru	m = cd->mreq;
805104862Sru	if (m == NULL) {
806151497Sru		xprt_inactive_self(xprt);
807104862Sru		mtx_unlock(&ct->ct_lock);
808104862Sru		sx_xunlock(&xprt->xp_lock);
809104862Sru		return (FALSE);
810104862Sru	}
811104862Sru	cd->mreq = m->m_nextpkt;
812151497Sru	mtx_unlock(&ct->ct_lock);
813151497Sru	sx_xunlock(&xprt->xp_lock);
814151497Sru
815104862Sru	xdrmbuf_create(&xdrs, m, XDR_DECODE);
816114402Sru	if (! xdr_callmsg(&xdrs, msg)) {
817104862Sru		XDR_DESTROY(&xdrs);
818104862Sru		return (FALSE);
819104862Sru	}
820151497Sru	*addrp = NULL;
821104862Sru	*mp = xdrmbuf_getall(&xdrs);
822104862Sru	XDR_DESTROY(&xdrs);
823104862Sru	return (TRUE);
824104862Sru}
825104862Sru
826104862Srustatic bool_t
827104862Srusvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
828151497Sru    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
829151497Sru{
830104862Sru	XDR xdrs;
831151497Sru	struct mbuf *mrep;
832104862Sru	bool_t stat = TRUE;
833104862Sru	int error, len;
834114402Sru
835151497Sru	/*
836114402Sru	 * Leave space for record mark.
837151497Sru	 */
838151497Sru	mrep = m_gethdr(M_WAITOK, MT_DATA);
839151497Sru	mrep->m_data += sizeof(uint32_t);
840151497Sru
841151497Sru	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
842151497Sru
843151497Sru	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
844151497Sru	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
845151497Sru		if (!xdr_replymsg(&xdrs, msg))
846151497Sru			stat = FALSE;
847151497Sru		else
848151497Sru			xdrmbuf_append(&xdrs, m);
849151497Sru	} else {
850151497Sru		stat = xdr_replymsg(&xdrs, msg);
851151497Sru	}
852151497Sru
853151497Sru	if (stat) {
854151497Sru		m_fixhdr(mrep);
855151497Sru
856151497Sru		/*
857151497Sru		 * Prepend a record marker containing the reply length.
858151497Sru		 */
859104862Sru		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
860151497Sru		len = mrep->m_pkthdr.len;
861151497Sru		*mtod(mrep, uint32_t *) =
862151497Sru			htonl(0x80000000 | (len - sizeof(uint32_t)));
863151497Sru		atomic_add_acq_32(&xprt->xp_snd_cnt, len);
864151497Sru		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
865151497Sru		    0, curthread);
866151497Sru		if (!error) {
867151497Sru			atomic_add_rel_32(&xprt->xp_snt_cnt, len);
868151497Sru			if (seq)
869151497Sru				*seq = xprt->xp_snd_cnt;
870151497Sru			stat = TRUE;
871104862Sru		} else
872151497Sru			atomic_subtract_32(&xprt->xp_snd_cnt, len);
873151497Sru	} else {
874151497Sru		m_freem(mrep);
875151497Sru	}
876151497Sru
877151497Sru	XDR_DESTROY(&xdrs);
878151497Sru
879151497Sru	return (stat);
880151497Sru}
881151497Sru
882151497Srustatic bool_t
883151497Srusvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
884104862Sru    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
885104862Sru{
886104862Sru	struct ct_data *ct;
887151497Sru	XDR xdrs;
888151497Sru	struct mbuf *mrep;
889151497Sru	bool_t stat = TRUE;
890151497Sru	int error;
891104862Sru
892104862Sru	/*
893104862Sru	 * Leave space for record mark.
894104862Sru	 */
895151497Sru	mrep = m_gethdr(M_WAITOK, MT_DATA);
896151497Sru	mrep->m_data += sizeof(uint32_t);
897151497Sru
898151497Sru	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
899104862Sru
900151497Sru	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
901151497Sru	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
902151497Sru		if (!xdr_replymsg(&xdrs, msg))
903151497Sru			stat = FALSE;
904151497Sru		else
905151497Sru			xdrmbuf_append(&xdrs, m);
906151497Sru	} else {
907151497Sru		stat = xdr_replymsg(&xdrs, msg);
908151497Sru	}
909151497Sru
910151497Sru	if (stat) {
911151497Sru		m_fixhdr(mrep);
912151497Sru
913151497Sru		/*
914151497Sru		 * Prepend a record marker containing the reply length.
915151497Sru		 */
916151497Sru		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
917151497Sru		*mtod(mrep, uint32_t *) =
918114402Sru			htonl(0x80000000 | (mrep->m_pkthdr.len
919104862Sru				- sizeof(uint32_t)));
920104862Sru		sx_xlock(&xprt->xp_lock);
921104862Sru		ct = (struct ct_data *)xprt->xp_p2;
922104862Sru		if (ct != NULL)
923104862Sru			error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
924151497Sru			    0, curthread);
925151497Sru		else
926104862Sru			error = EPIPE;
927151497Sru		sx_xunlock(&xprt->xp_lock);
92875584Sru		if (!error) {
929151497Sru			stat = TRUE;
93075584Sru		}
93175584Sru	} else {
932114402Sru		m_freem(mrep);
933104862Sru	}
934104862Sru
935104862Sru	XDR_DESTROY(&xdrs);
936104862Sru
937104862Sru	return (stat);
938104862Sru}
939104862Sru
940104862Srustatic bool_t
941151497Srusvc_vc_null()
942151497Sru{
94375584Sru
944151497Sru	return (FALSE);
945151497Sru}
94675584Sru
947114402Srustatic int
948151497Srusvc_vc_soupcall(struct socket *so, void *arg, int waitflag)
949151497Sru{
950151497Sru	SVCXPRT *xprt = (SVCXPRT *) arg;
951151497Sru
952151497Sru	if (soreadable(xprt->xp_socket))
953151497Sru		xprt_active(xprt);
954151497Sru	return (SU_OK);
955151497Sru}
956151497Sru
957151497Sru#if 0
958151497Sru/*
959151497Sru * Get the effective UID of the sending process. Used by rpcbind, keyserv
960151497Sru * and rpc.yppasswdd on AF_LOCAL.
961151497Sru */
962151497Sruint
963151497Sru__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
964151497Sru	int sock, ret;
965151497Sru	gid_t egid;
966151497Sru	uid_t euid;
967151497Sru	struct sockaddr *sa;
968151497Sru
969151497Sru	sock = transp->xp_fd;
970151497Sru	sa = (struct sockaddr *)transp->xp_rtaddr;
971151497Sru	if (sa->sa_family == AF_LOCAL) {
972151497Sru		ret = getpeereid(sock, &euid, &egid);
973151497Sru		if (ret == 0)
974151497Sru			*uid = euid;
975151497Sru		return (ret);
976151497Sru	} else
977151497Sru		return (-1);
978151497Sru}
979151497Sru#endif
980151497Sru