1177633Sdfr/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
2177633Sdfr
3261057Smav/*-
4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261057Smav * All rights reserved.
6261057Smav *
7261057Smav * Redistribution and use in source and binary forms, with or without
8261057Smav * modification, are permitted provided that the following conditions are met:
9261057Smav * - Redistributions of source code must retain the above copyright notice,
10261057Smav *   this list of conditions and the following disclaimer.
11261057Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261057Smav *   this list of conditions and the following disclaimer in the documentation
13261057Smav *   and/or other materials provided with the distribution.
14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261057Smav *   contributors may be used to endorse or promote products derived
16261057Smav *   from this software without specific prior written permission.
17177633Sdfr *
18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261057Smav * POSSIBILITY OF SUCH DAMAGE.
29177633Sdfr */
30177633Sdfr
31177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
32177633Sdfrstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
33177633Sdfrstatic char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
34177633Sdfr#endif
35177633Sdfr#include <sys/cdefs.h>
36177633Sdfr__FBSDID("$FreeBSD$");
37177633Sdfr
38177633Sdfr/*
39177633Sdfr * svc_vc.c, Server side for Connection Oriented based RPC.
40177633Sdfr *
41177633Sdfr * Actually implements two flavors of transporter -
42177633Sdfr * a tcp rendezvouser (a listner and connection establisher)
43177633Sdfr * and a record/tcp stream.
44177633Sdfr */
45177633Sdfr
46177633Sdfr#include <sys/param.h>
47261082Smav#include <sys/limits.h>
48177633Sdfr#include <sys/lock.h>
49177633Sdfr#include <sys/kernel.h>
50177633Sdfr#include <sys/malloc.h>
51177633Sdfr#include <sys/mbuf.h>
52177633Sdfr#include <sys/mutex.h>
53193509Srwatson#include <sys/proc.h>
54177633Sdfr#include <sys/protosw.h>
55177633Sdfr#include <sys/queue.h>
56177633Sdfr#include <sys/socket.h>
57177633Sdfr#include <sys/socketvar.h>
58184588Sdfr#include <sys/sx.h>
59177633Sdfr#include <sys/systm.h>
60177633Sdfr#include <sys/uio.h>
61196503Szec
62196503Szec#include <net/vnet.h>
63196503Szec
64177633Sdfr#include <netinet/tcp.h>
65177633Sdfr
66177633Sdfr#include <rpc/rpc.h>
67177633Sdfr
68261058Smav#include <rpc/krpc.h>
69177685Sdfr#include <rpc/rpc_com.h>
70177633Sdfr
71193509Srwatson#include <security/mac/mac_framework.h>
72193509Srwatson
73184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
74184588Sdfr    struct sockaddr **, struct mbuf **);
75177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
76177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *);
77177633Sdfrstatic bool_t svc_vc_null(void);
78177633Sdfrstatic void svc_vc_destroy(SVCXPRT *);
79177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *);
80261067Smavstatic bool_t svc_vc_ack(SVCXPRT *, uint32_t *);
81184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
82184588Sdfr    struct sockaddr **, struct mbuf **);
83184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
84261067Smav    struct sockaddr *, struct mbuf *, uint32_t *seq);
85177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
86177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
87177633Sdfr    void *in);
88261058Smavstatic void svc_vc_backchannel_destroy(SVCXPRT *);
89261058Smavstatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
90261058Smavstatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
91261058Smav    struct sockaddr **, struct mbuf **);
92261058Smavstatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
93261067Smav    struct sockaddr *, struct mbuf *, uint32_t *);
94261058Smavstatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
95261058Smav    void *in);
96177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
97177633Sdfr    struct sockaddr *raddr);
98177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop);
99193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
100177633Sdfr
101177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = {
102177633Sdfr	.xp_recv =	svc_vc_rendezvous_recv,
103177633Sdfr	.xp_stat =	svc_vc_rendezvous_stat,
104184588Sdfr	.xp_reply =	(bool_t (*)(SVCXPRT *, struct rpc_msg *,
105261067Smav		struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null,
106177633Sdfr	.xp_destroy =	svc_vc_rendezvous_destroy,
107177633Sdfr	.xp_control =	svc_vc_rendezvous_control
108177633Sdfr};
109177633Sdfr
110177633Sdfrstatic struct xp_ops svc_vc_ops = {
111177633Sdfr	.xp_recv =	svc_vc_recv,
112177633Sdfr	.xp_stat =	svc_vc_stat,
113261067Smav	.xp_ack =	svc_vc_ack,
114177633Sdfr	.xp_reply =	svc_vc_reply,
115177633Sdfr	.xp_destroy =	svc_vc_destroy,
116177633Sdfr	.xp_control =	svc_vc_control
117177633Sdfr};
118177633Sdfr
119261058Smavstatic struct xp_ops svc_vc_backchannel_ops = {
120261058Smav	.xp_recv =	svc_vc_backchannel_recv,
121261058Smav	.xp_stat =	svc_vc_backchannel_stat,
122261058Smav	.xp_reply =	svc_vc_backchannel_reply,
123261058Smav	.xp_destroy =	svc_vc_backchannel_destroy,
124261058Smav	.xp_control =	svc_vc_backchannel_control
125177633Sdfr};
126177633Sdfr
127177633Sdfr/*
128177633Sdfr * Usage:
129177633Sdfr *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
130177633Sdfr *
131177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter.
132177633Sdfr * Once *xprt is initialized, it is registered as a transporter
133177633Sdfr * see (svc.h, xprt_register).  This routine returns
134177633Sdfr * a NULL if a problem occurred.
135177633Sdfr *
136177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but
137177633Sdfr * not yet connected socket.
138177633Sdfr *
139177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify
140177633Sdfr * how big the send and receive buffers are via the second and third parms;
141177633Sdfr * 0 => use the system default.
142177633Sdfr */
143177633SdfrSVCXPRT *
144177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
145177633Sdfr    size_t recvsize)
146177633Sdfr{
147177633Sdfr	SVCXPRT *xprt;
148177633Sdfr	struct sockaddr* sa;
149177633Sdfr	int error;
150177633Sdfr
151251698Sjhb	SOCK_LOCK(so);
152251698Sjhb	if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) {
153251698Sjhb		SOCK_UNLOCK(so);
154180025Sdfr		error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
155180025Sdfr		if (error)
156180025Sdfr			return (NULL);
157180025Sdfr		xprt = svc_vc_create_conn(pool, so, sa);
158180025Sdfr		free(sa, M_SONAME);
159180025Sdfr		return (xprt);
160180025Sdfr	}
161251698Sjhb	SOCK_UNLOCK(so);
162180025Sdfr
163184588Sdfr	xprt = svc_xprt_alloc();
164184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
165177633Sdfr	xprt->xp_pool = pool;
166177633Sdfr	xprt->xp_socket = so;
167177633Sdfr	xprt->xp_p1 = NULL;
168177633Sdfr	xprt->xp_p2 = NULL;
169177633Sdfr	xprt->xp_ops = &svc_vc_rendezvous_ops;
170177633Sdfr
171177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
172196503Szec	if (error) {
173177633Sdfr		goto cleanup_svc_vc_create;
174196503Szec	}
175177633Sdfr
176184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
177177633Sdfr	free(sa, M_SONAME);
178177633Sdfr
179177633Sdfr	xprt_register(xprt);
180177633Sdfr
181177633Sdfr	solisten(so, SOMAXCONN, curthread);
182177633Sdfr
183177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
184193436Srmacklem	xprt->xp_upcallset = 1;
185193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
186177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
187177633Sdfr
188177633Sdfr	return (xprt);
189177633Sdfrcleanup_svc_vc_create:
190261067Smav	if (xprt) {
191261067Smav		sx_destroy(&xprt->xp_lock);
192184588Sdfr		svc_xprt_free(xprt);
193261067Smav	}
194177633Sdfr	return (NULL);
195177633Sdfr}
196177633Sdfr
197177633Sdfr/*
198177633Sdfr * Create a new transport for a socket optained via soaccept().
199177633Sdfr */
200177633SdfrSVCXPRT *
201177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
202177633Sdfr{
203177633Sdfr	SVCXPRT *xprt = NULL;
204177633Sdfr	struct cf_conn *cd = NULL;
205177633Sdfr	struct sockaddr* sa = NULL;
206180025Sdfr	struct sockopt opt;
207180025Sdfr	int one = 1;
208177633Sdfr	int error;
209177633Sdfr
210180025Sdfr	bzero(&opt, sizeof(struct sockopt));
211180025Sdfr	opt.sopt_dir = SOPT_SET;
212180025Sdfr	opt.sopt_level = SOL_SOCKET;
213180025Sdfr	opt.sopt_name = SO_KEEPALIVE;
214180025Sdfr	opt.sopt_val = &one;
215180025Sdfr	opt.sopt_valsize = sizeof(one);
216180025Sdfr	error = sosetopt(so, &opt);
217196503Szec	if (error) {
218180025Sdfr		return (NULL);
219196503Szec	}
220180025Sdfr
221180025Sdfr	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
222180025Sdfr		bzero(&opt, sizeof(struct sockopt));
223180025Sdfr		opt.sopt_dir = SOPT_SET;
224180025Sdfr		opt.sopt_level = IPPROTO_TCP;
225180025Sdfr		opt.sopt_name = TCP_NODELAY;
226180025Sdfr		opt.sopt_val = &one;
227180025Sdfr		opt.sopt_valsize = sizeof(one);
228180025Sdfr		error = sosetopt(so, &opt);
229196503Szec		if (error) {
230180025Sdfr			return (NULL);
231196503Szec		}
232180025Sdfr	}
233180025Sdfr
234177633Sdfr	cd = mem_alloc(sizeof(*cd));
235177633Sdfr	cd->strm_stat = XPRT_IDLE;
236177633Sdfr
237184588Sdfr	xprt = svc_xprt_alloc();
238184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
239177633Sdfr	xprt->xp_pool = pool;
240177633Sdfr	xprt->xp_socket = so;
241177633Sdfr	xprt->xp_p1 = cd;
242177633Sdfr	xprt->xp_p2 = NULL;
243177633Sdfr	xprt->xp_ops = &svc_vc_ops;
244177633Sdfr
245184588Sdfr	/*
246184588Sdfr	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
247184588Sdfr	 * has a 5 minute timer, server has a 6 minute timer.
248184588Sdfr	 */
249184588Sdfr	xprt->xp_idletimeout = 6 * 60;
250177633Sdfr
251184588Sdfr	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
252184588Sdfr
253177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
254177633Sdfr	if (error)
255177633Sdfr		goto cleanup_svc_vc_create;
256177633Sdfr
257184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
258177633Sdfr	free(sa, M_SONAME);
259177633Sdfr
260177633Sdfr	xprt_register(xprt);
261177633Sdfr
262177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
263193436Srmacklem	xprt->xp_upcallset = 1;
264193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
265177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
266177633Sdfr
267177633Sdfr	/*
268177633Sdfr	 * Throw the transport into the active list in case it already
269177633Sdfr	 * has some data buffered.
270177633Sdfr	 */
271184588Sdfr	sx_xlock(&xprt->xp_lock);
272177633Sdfr	xprt_active(xprt);
273184588Sdfr	sx_xunlock(&xprt->xp_lock);
274177633Sdfr
275177633Sdfr	return (xprt);
276177633Sdfrcleanup_svc_vc_create:
277177633Sdfr	if (xprt) {
278261067Smav		sx_destroy(&xprt->xp_lock);
279261067Smav		svc_xprt_free(xprt);
280177633Sdfr	}
281177633Sdfr	if (cd)
282177633Sdfr		mem_free(cd, sizeof(*cd));
283177633Sdfr	return (NULL);
284177633Sdfr}
285177633Sdfr
286177633Sdfr/*
287261058Smav * Create a new transport for a backchannel on a clnt_vc socket.
288261058Smav */
289261058SmavSVCXPRT *
290261058Smavsvc_vc_create_backchannel(SVCPOOL *pool)
291261058Smav{
292261058Smav	SVCXPRT *xprt = NULL;
293261058Smav	struct cf_conn *cd = NULL;
294261058Smav
295261058Smav	cd = mem_alloc(sizeof(*cd));
296261058Smav	cd->strm_stat = XPRT_IDLE;
297261058Smav
298261058Smav	xprt = svc_xprt_alloc();
299261058Smav	sx_init(&xprt->xp_lock, "xprt->xp_lock");
300261058Smav	xprt->xp_pool = pool;
301261058Smav	xprt->xp_socket = NULL;
302261058Smav	xprt->xp_p1 = cd;
303261058Smav	xprt->xp_p2 = NULL;
304261058Smav	xprt->xp_ops = &svc_vc_backchannel_ops;
305261058Smav	return (xprt);
306261058Smav}
307261058Smav
308261058Smav/*
309177633Sdfr * This does all of the accept except the final call to soaccept. The
310177633Sdfr * caller will call soaccept after dropping its locks (soaccept may
311177633Sdfr * call malloc).
312177633Sdfr */
313177633Sdfrint
314177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop)
315177633Sdfr{
316177633Sdfr	int error = 0;
317177633Sdfr	struct socket *so;
318177633Sdfr
319177633Sdfr	if ((head->so_options & SO_ACCEPTCONN) == 0) {
320177633Sdfr		error = EINVAL;
321177633Sdfr		goto done;
322177633Sdfr	}
323177633Sdfr#ifdef MAC
324193509Srwatson	error = mac_socket_check_accept(curthread->td_ucred, head);
325177633Sdfr	if (error != 0)
326177633Sdfr		goto done;
327177633Sdfr#endif
328177633Sdfr	ACCEPT_LOCK();
329177633Sdfr	if (TAILQ_EMPTY(&head->so_comp)) {
330177633Sdfr		ACCEPT_UNLOCK();
331177633Sdfr		error = EWOULDBLOCK;
332177633Sdfr		goto done;
333177633Sdfr	}
334177633Sdfr	so = TAILQ_FIRST(&head->so_comp);
335177633Sdfr	KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
336177633Sdfr	KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
337177633Sdfr
338177633Sdfr	/*
339177633Sdfr	 * Before changing the flags on the socket, we have to bump the
340177633Sdfr	 * reference count.  Otherwise, if the protocol calls sofree(),
341177633Sdfr	 * the socket will be released due to a zero refcount.
342177633Sdfr	 * XXX might not need soref() since this is simpler than kern_accept.
343177633Sdfr	 */
344177633Sdfr	SOCK_LOCK(so);			/* soref() and so_state update */
345177633Sdfr	soref(so);			/* file descriptor reference */
346177633Sdfr
347177633Sdfr	TAILQ_REMOVE(&head->so_comp, so, so_list);
348177633Sdfr	head->so_qlen--;
349177633Sdfr	so->so_state |= (head->so_state & SS_NBIO);
350177633Sdfr	so->so_qstate &= ~SQ_COMP;
351177633Sdfr	so->so_head = NULL;
352177633Sdfr
353177633Sdfr	SOCK_UNLOCK(so);
354177633Sdfr	ACCEPT_UNLOCK();
355177633Sdfr
356177633Sdfr	*sop = so;
357177633Sdfr
358177633Sdfr	/* connection has been removed from the listen queue */
359177633Sdfr	KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
360177633Sdfrdone:
361177633Sdfr	return (error);
362177633Sdfr}
363177633Sdfr
364177633Sdfr/*ARGSUSED*/
365177633Sdfrstatic bool_t
366184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
367184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
368177633Sdfr{
369177633Sdfr	struct socket *so = NULL;
370177633Sdfr	struct sockaddr *sa = NULL;
371177633Sdfr	int error;
372194407Srmacklem	SVCXPRT *new_xprt;
373177633Sdfr
374177633Sdfr	/*
375177633Sdfr	 * The socket upcall calls xprt_active() which will eventually
376177633Sdfr	 * cause the server to call us here. We attempt to accept a
377177633Sdfr	 * connection from the socket and turn it into a new
378177633Sdfr	 * transport. If the accept fails, we have drained all pending
379177633Sdfr	 * connections so we call xprt_inactive().
380177633Sdfr	 */
381184588Sdfr	sx_xlock(&xprt->xp_lock);
382177633Sdfr
383177633Sdfr	error = svc_vc_accept(xprt->xp_socket, &so);
384177633Sdfr
385177633Sdfr	if (error == EWOULDBLOCK) {
386184588Sdfr		/*
387184588Sdfr		 * We must re-test for new connections after taking
388184588Sdfr		 * the lock to protect us in the case where a new
389184588Sdfr		 * connection arrives after our call to accept fails
390261059Smav		 * with EWOULDBLOCK.
391184588Sdfr		 */
392184588Sdfr		ACCEPT_LOCK();
393184588Sdfr		if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
394261065Smav			xprt_inactive_self(xprt);
395184588Sdfr		ACCEPT_UNLOCK();
396184588Sdfr		sx_xunlock(&xprt->xp_lock);
397177633Sdfr		return (FALSE);
398177633Sdfr	}
399177633Sdfr
400177633Sdfr	if (error) {
401177633Sdfr		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
402193436Srmacklem		if (xprt->xp_upcallset) {
403193436Srmacklem			xprt->xp_upcallset = 0;
404193436Srmacklem			soupcall_clear(xprt->xp_socket, SO_RCV);
405193436Srmacklem		}
406177633Sdfr		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
407261065Smav		xprt_inactive_self(xprt);
408184588Sdfr		sx_xunlock(&xprt->xp_lock);
409177633Sdfr		return (FALSE);
410177633Sdfr	}
411177633Sdfr
412184588Sdfr	sx_xunlock(&xprt->xp_lock);
413177633Sdfr
414177633Sdfr	sa = 0;
415177633Sdfr	error = soaccept(so, &sa);
416177633Sdfr
417177633Sdfr	if (error) {
418177633Sdfr		/*
419177633Sdfr		 * XXX not sure if I need to call sofree or soclose here.
420177633Sdfr		 */
421177633Sdfr		if (sa)
422177633Sdfr			free(sa, M_SONAME);
423177633Sdfr		return (FALSE);
424177633Sdfr	}
425177633Sdfr
426177633Sdfr	/*
427177633Sdfr	 * svc_vc_create_conn will call xprt_register - we don't need
428194407Srmacklem	 * to do anything with the new connection except derefence it.
429177633Sdfr	 */
430194407Srmacklem	new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
431194407Srmacklem	if (!new_xprt) {
432180025Sdfr		soclose(so);
433194407Srmacklem	} else {
434194407Srmacklem		SVC_RELEASE(new_xprt);
435194407Srmacklem	}
436180025Sdfr
437177633Sdfr	free(sa, M_SONAME);
438177633Sdfr
439177633Sdfr	return (FALSE); /* there is never an rpc msg to be processed */
440177633Sdfr}
441177633Sdfr
442177633Sdfr/*ARGSUSED*/
443177633Sdfrstatic enum xprt_stat
444177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt)
445177633Sdfr{
446177633Sdfr
447177633Sdfr	return (XPRT_IDLE);
448177633Sdfr}
449177633Sdfr
450177633Sdfrstatic void
451177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt)
452177633Sdfr{
453177633Sdfr	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
454193436Srmacklem	if (xprt->xp_upcallset) {
455193436Srmacklem		xprt->xp_upcallset = 0;
456193436Srmacklem		soupcall_clear(xprt->xp_socket, SO_RCV);
457193436Srmacklem	}
458177633Sdfr	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
459177633Sdfr
460177633Sdfr	if (xprt->xp_socket)
461177633Sdfr		(void)soclose(xprt->xp_socket);
462177633Sdfr
463184588Sdfr	if (xprt->xp_netid)
464184588Sdfr		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
465184588Sdfr	svc_xprt_free(xprt);
466177633Sdfr}
467177633Sdfr
468177633Sdfrstatic void
469177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt)
470177633Sdfr{
471177633Sdfr
472177633Sdfr	svc_vc_destroy_common(xprt);
473177633Sdfr}
474177633Sdfr
475177633Sdfrstatic void
476177633Sdfrsvc_vc_destroy(SVCXPRT *xprt)
477177633Sdfr{
478177633Sdfr	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
479177633Sdfr
480177633Sdfr	svc_vc_destroy_common(xprt);
481177633Sdfr
482177633Sdfr	if (cd->mreq)
483177633Sdfr		m_freem(cd->mreq);
484177633Sdfr	if (cd->mpending)
485177633Sdfr		m_freem(cd->mpending);
486177633Sdfr	mem_free(cd, sizeof(*cd));
487177633Sdfr}
488177633Sdfr
489261058Smavstatic void
490261058Smavsvc_vc_backchannel_destroy(SVCXPRT *xprt)
491261058Smav{
492261058Smav	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
493261058Smav	struct mbuf *m, *m2;
494261058Smav
495261058Smav	svc_xprt_free(xprt);
496261058Smav	m = cd->mreq;
497261058Smav	while (m != NULL) {
498261058Smav		m2 = m;
499261058Smav		m = m->m_nextpkt;
500261058Smav		m_freem(m2);
501261058Smav	}
502261058Smav	mem_free(cd, sizeof(*cd));
503261058Smav}
504261058Smav
505177633Sdfr/*ARGSUSED*/
506177633Sdfrstatic bool_t
507177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
508177633Sdfr{
509177633Sdfr	return (FALSE);
510177633Sdfr}
511177633Sdfr
512177633Sdfrstatic bool_t
513177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
514177633Sdfr{
515177633Sdfr
516177633Sdfr	return (FALSE);
517177633Sdfr}
518177633Sdfr
519261058Smavstatic bool_t
520261058Smavsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
521261058Smav{
522261058Smav
523261058Smav	return (FALSE);
524261058Smav}
525261058Smav
526177633Sdfrstatic enum xprt_stat
527177633Sdfrsvc_vc_stat(SVCXPRT *xprt)
528177633Sdfr{
529177633Sdfr	struct cf_conn *cd;
530177633Sdfr
531177633Sdfr	cd = (struct cf_conn *)(xprt->xp_p1);
532177633Sdfr
533177633Sdfr	if (cd->strm_stat == XPRT_DIED)
534177633Sdfr		return (XPRT_DIED);
535177633Sdfr
536261059Smav	if (cd->mreq != NULL && cd->resid == 0 && cd->eor)
537261059Smav		return (XPRT_MOREREQS);
538177633Sdfr
539184588Sdfr	if (soreadable(xprt->xp_socket))
540184588Sdfr		return (XPRT_MOREREQS);
541184588Sdfr
542177633Sdfr	return (XPRT_IDLE);
543177633Sdfr}
544177633Sdfr
545261067Smavstatic bool_t
546261067Smavsvc_vc_ack(SVCXPRT *xprt, uint32_t *ack)
547261067Smav{
548261067Smav
549261067Smav	*ack = atomic_load_acq_32(&xprt->xp_snt_cnt);
550261067Smav	*ack -= xprt->xp_socket->so_snd.sb_cc;
551261067Smav	return (TRUE);
552261067Smav}
553261067Smav
554261058Smavstatic enum xprt_stat
555261058Smavsvc_vc_backchannel_stat(SVCXPRT *xprt)
556261058Smav{
557261058Smav	struct cf_conn *cd;
558261058Smav
559261058Smav	cd = (struct cf_conn *)(xprt->xp_p1);
560261058Smav
561261058Smav	if (cd->mreq != NULL)
562261058Smav		return (XPRT_MOREREQS);
563261058Smav
564261058Smav	return (XPRT_IDLE);
565261058Smav}
566261058Smav
567261059Smav/*
568261059Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it,
569261059Smav * leaving the result in cd->mreq. If we don't have a complete record, leave
570261059Smav * the partial result in cd->mreq and try to read more from the socket.
571261059Smav */
572261062Smavstatic int
573261059Smavsvc_vc_process_pending(SVCXPRT *xprt)
574261059Smav{
575261059Smav	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
576261059Smav	struct socket *so = xprt->xp_socket;
577261059Smav	struct mbuf *m;
578261059Smav
579261059Smav	/*
580261059Smav	 * If cd->resid is non-zero, we have part of the
581261059Smav	 * record already, otherwise we are expecting a record
582261059Smav	 * marker.
583261059Smav	 */
584261059Smav	if (!cd->resid && cd->mpending) {
585261059Smav		/*
586261059Smav		 * See if there is enough data buffered to
587261059Smav		 * make up a record marker. Make sure we can
588261059Smav		 * handle the case where the record marker is
589261059Smav		 * split across more than one mbuf.
590261059Smav		 */
591261059Smav		size_t n = 0;
592261059Smav		uint32_t header;
593261059Smav
594261059Smav		m = cd->mpending;
595261059Smav		while (n < sizeof(uint32_t) && m) {
596261059Smav			n += m->m_len;
597261059Smav			m = m->m_next;
598261059Smav		}
599261059Smav		if (n < sizeof(uint32_t)) {
600261059Smav			so->so_rcv.sb_lowat = sizeof(uint32_t) - n;
601261062Smav			return (FALSE);
602261059Smav		}
603261059Smav		m_copydata(cd->mpending, 0, sizeof(header),
604261059Smav		    (char *)&header);
605261059Smav		header = ntohl(header);
606261059Smav		cd->eor = (header & 0x80000000) != 0;
607261059Smav		cd->resid = header & 0x7fffffff;
608261059Smav		m_adj(cd->mpending, sizeof(uint32_t));
609261059Smav	}
610261059Smav
611261059Smav	/*
612261059Smav	 * Start pulling off mbufs from cd->mpending
613261059Smav	 * until we either have a complete record or
614261059Smav	 * we run out of data. We use m_split to pull
615261059Smav	 * data - it will pull as much as possible and
616261059Smav	 * split the last mbuf if necessary.
617261059Smav	 */
618261059Smav	while (cd->mpending && cd->resid) {
619261059Smav		m = cd->mpending;
620261059Smav		if (cd->mpending->m_next
621261059Smav		    || cd->mpending->m_len > cd->resid)
622261059Smav			cd->mpending = m_split(cd->mpending,
623261059Smav			    cd->resid, M_WAITOK);
624261059Smav		else
625261059Smav			cd->mpending = NULL;
626261059Smav		if (cd->mreq)
627261059Smav			m_last(cd->mreq)->m_next = m;
628261059Smav		else
629261059Smav			cd->mreq = m;
630261059Smav		while (m) {
631261059Smav			cd->resid -= m->m_len;
632261059Smav			m = m->m_next;
633261059Smav		}
634261059Smav	}
635261059Smav
636261064Smav	/*
637261064Smav	 * Block receive upcalls if we have more data pending,
638261064Smav	 * otherwise report our need.
639261064Smav	 */
640261064Smav	if (cd->mpending)
641261064Smav		so->so_rcv.sb_lowat = INT_MAX;
642261064Smav	else
643261064Smav		so->so_rcv.sb_lowat =
644261064Smav		    imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2));
645261062Smav	return (TRUE);
646261059Smav}
647261059Smav
648177633Sdfrstatic bool_t
649184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
650184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
651177633Sdfr{
652177633Sdfr	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
653177633Sdfr	struct uio uio;
654177633Sdfr	struct mbuf *m;
655261059Smav	struct socket* so = xprt->xp_socket;
656184588Sdfr	XDR xdrs;
657177633Sdfr	int error, rcvflag;
658177633Sdfr
659184588Sdfr	/*
660184588Sdfr	 * Serialise access to the socket and our own record parsing
661184588Sdfr	 * state.
662184588Sdfr	 */
663184588Sdfr	sx_xlock(&xprt->xp_lock);
664184588Sdfr
665177633Sdfr	for (;;) {
666261059Smav		/* If we have no request ready, check pending queue. */
667261059Smav		while (cd->mpending &&
668261062Smav		    (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) {
669261062Smav			if (!svc_vc_process_pending(xprt))
670261062Smav				break;
671261062Smav		}
672177633Sdfr
673261059Smav		/* Process and return complete request in cd->mreq. */
674261059Smav		if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
675177633Sdfr
676261059Smav			xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
677261059Smav			cd->mreq = NULL;
678261059Smav
679261059Smav			/* Check for next request in a pending queue. */
680261059Smav			svc_vc_process_pending(xprt);
681261059Smav			if (cd->mreq == NULL || cd->resid != 0) {
682261059Smav				SOCKBUF_LOCK(&so->so_rcv);
683261059Smav				if (!soreadable(so))
684261065Smav					xprt_inactive_self(xprt);
685261059Smav				SOCKBUF_UNLOCK(&so->so_rcv);
686177633Sdfr			}
687177633Sdfr
688261059Smav			sx_xunlock(&xprt->xp_lock);
689177633Sdfr
690261059Smav			if (! xdr_callmsg(&xdrs, msg)) {
691261059Smav				XDR_DESTROY(&xdrs);
692261059Smav				return (FALSE);
693261059Smav			}
694184588Sdfr
695261059Smav			*addrp = NULL;
696261059Smav			*mp = xdrmbuf_getall(&xdrs);
697261059Smav			XDR_DESTROY(&xdrs);
698177633Sdfr
699261059Smav			return (TRUE);
700177633Sdfr		}
701177633Sdfr
702177633Sdfr		/*
703177633Sdfr		 * The socket upcall calls xprt_active() which will eventually
704177633Sdfr		 * cause the server to call us here. We attempt to
705177633Sdfr		 * read as much as possible from the socket and put
706177633Sdfr		 * the result in cd->mpending. If the read fails,
707177633Sdfr		 * we have drained both cd->mpending and the socket so
708177633Sdfr		 * we can call xprt_inactive().
709177633Sdfr		 */
710177633Sdfr		uio.uio_resid = 1000000000;
711177633Sdfr		uio.uio_td = curthread;
712177633Sdfr		m = NULL;
713177633Sdfr		rcvflag = MSG_DONTWAIT;
714261059Smav		error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
715177633Sdfr
716177633Sdfr		if (error == EWOULDBLOCK) {
717184588Sdfr			/*
718184588Sdfr			 * We must re-test for readability after
719184588Sdfr			 * taking the lock to protect us in the case
720184588Sdfr			 * where a new packet arrives on the socket
721184588Sdfr			 * after our call to soreceive fails with
722261059Smav			 * EWOULDBLOCK.
723184588Sdfr			 */
724261059Smav			SOCKBUF_LOCK(&so->so_rcv);
725261059Smav			if (!soreadable(so))
726261065Smav				xprt_inactive_self(xprt);
727261059Smav			SOCKBUF_UNLOCK(&so->so_rcv);
728184588Sdfr			sx_xunlock(&xprt->xp_lock);
729177633Sdfr			return (FALSE);
730177633Sdfr		}
731177633Sdfr
732177633Sdfr		if (error) {
733261059Smav			SOCKBUF_LOCK(&so->so_rcv);
734193436Srmacklem			if (xprt->xp_upcallset) {
735193436Srmacklem				xprt->xp_upcallset = 0;
736261059Smav				soupcall_clear(so, SO_RCV);
737193436Srmacklem			}
738261059Smav			SOCKBUF_UNLOCK(&so->so_rcv);
739261065Smav			xprt_inactive_self(xprt);
740177633Sdfr			cd->strm_stat = XPRT_DIED;
741184588Sdfr			sx_xunlock(&xprt->xp_lock);
742177633Sdfr			return (FALSE);
743177633Sdfr		}
744177633Sdfr
745177633Sdfr		if (!m) {
746177633Sdfr			/*
747177633Sdfr			 * EOF - the other end has closed the socket.
748177633Sdfr			 */
749261065Smav			xprt_inactive_self(xprt);
750177633Sdfr			cd->strm_stat = XPRT_DIED;
751184588Sdfr			sx_xunlock(&xprt->xp_lock);
752177633Sdfr			return (FALSE);
753177633Sdfr		}
754177633Sdfr
755177633Sdfr		if (cd->mpending)
756177633Sdfr			m_last(cd->mpending)->m_next = m;
757177633Sdfr		else
758177633Sdfr			cd->mpending = m;
759177633Sdfr	}
760177633Sdfr}
761177633Sdfr
762177633Sdfrstatic bool_t
763261058Smavsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
764261058Smav    struct sockaddr **addrp, struct mbuf **mp)
765261058Smav{
766261058Smav	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
767261058Smav	struct ct_data *ct;
768261058Smav	struct mbuf *m;
769261058Smav	XDR xdrs;
770261058Smav
771261058Smav	sx_xlock(&xprt->xp_lock);
772261058Smav	ct = (struct ct_data *)xprt->xp_p2;
773261058Smav	if (ct == NULL) {
774261058Smav		sx_xunlock(&xprt->xp_lock);
775261058Smav		return (FALSE);
776261058Smav	}
777261058Smav	mtx_lock(&ct->ct_lock);
778261058Smav	m = cd->mreq;
779261058Smav	if (m == NULL) {
780261065Smav		xprt_inactive_self(xprt);
781261058Smav		mtx_unlock(&ct->ct_lock);
782261058Smav		sx_xunlock(&xprt->xp_lock);
783261058Smav		return (FALSE);
784261058Smav	}
785261058Smav	cd->mreq = m->m_nextpkt;
786261058Smav	mtx_unlock(&ct->ct_lock);
787261058Smav	sx_xunlock(&xprt->xp_lock);
788261058Smav
789261058Smav	xdrmbuf_create(&xdrs, m, XDR_DECODE);
790261058Smav	if (! xdr_callmsg(&xdrs, msg)) {
791261058Smav		XDR_DESTROY(&xdrs);
792261058Smav		return (FALSE);
793261058Smav	}
794261058Smav	*addrp = NULL;
795261058Smav	*mp = xdrmbuf_getall(&xdrs);
796261058Smav	XDR_DESTROY(&xdrs);
797261058Smav	return (TRUE);
798261058Smav}
799261058Smav
800261058Smavstatic bool_t
801184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
802261067Smav    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
803177633Sdfr{
804177633Sdfr	XDR xdrs;
805177633Sdfr	struct mbuf *mrep;
806184588Sdfr	bool_t stat = TRUE;
807261067Smav	int error, len;
808177633Sdfr
809177633Sdfr	/*
810177633Sdfr	 * Leave space for record mark.
811177633Sdfr	 */
812177633Sdfr	MGETHDR(mrep, M_WAIT, MT_DATA);
813177633Sdfr	mrep->m_len = 0;
814177633Sdfr	mrep->m_data += sizeof(uint32_t);
815177633Sdfr
816184588Sdfr	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
817184588Sdfr
818184588Sdfr	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
819184588Sdfr	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
820184588Sdfr		if (!xdr_replymsg(&xdrs, msg))
821184588Sdfr			stat = FALSE;
822184588Sdfr		else
823184588Sdfr			xdrmbuf_append(&xdrs, m);
824184588Sdfr	} else {
825184588Sdfr		stat = xdr_replymsg(&xdrs, msg);
826184588Sdfr	}
827184588Sdfr
828184588Sdfr	if (stat) {
829177633Sdfr		m_fixhdr(mrep);
830177633Sdfr
831177633Sdfr		/*
832177633Sdfr		 * Prepend a record marker containing the reply length.
833177633Sdfr		 */
834177633Sdfr		M_PREPEND(mrep, sizeof(uint32_t), M_WAIT);
835261067Smav		len = mrep->m_pkthdr.len;
836177633Sdfr		*mtod(mrep, uint32_t *) =
837261067Smav			htonl(0x80000000 | (len - sizeof(uint32_t)));
838261067Smav		atomic_add_acq_32(&xprt->xp_snd_cnt, len);
839177633Sdfr		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
840177633Sdfr		    0, curthread);
841177633Sdfr		if (!error) {
842261067Smav			atomic_add_rel_32(&xprt->xp_snt_cnt, len);
843261067Smav			if (seq)
844261067Smav				*seq = xprt->xp_snd_cnt;
845177633Sdfr			stat = TRUE;
846261067Smav		} else
847261067Smav			atomic_subtract_32(&xprt->xp_snd_cnt, len);
848177633Sdfr	} else {
849177633Sdfr		m_freem(mrep);
850177633Sdfr	}
851177633Sdfr
852184588Sdfr	XDR_DESTROY(&xdrs);
853177633Sdfr	xprt->xp_p2 = NULL;
854177633Sdfr
855177633Sdfr	return (stat);
856177633Sdfr}
857177633Sdfr
858177633Sdfrstatic bool_t
859261058Smavsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
860261067Smav    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
861261058Smav{
862261058Smav	struct ct_data *ct;
863261058Smav	XDR xdrs;
864261058Smav	struct mbuf *mrep;
865261058Smav	bool_t stat = TRUE;
866261058Smav	int error;
867261058Smav
868261058Smav	/*
869261058Smav	 * Leave space for record mark.
870261058Smav	 */
871261058Smav	MGETHDR(mrep, M_WAITOK, MT_DATA);
872261058Smav	mrep->m_len = 0;
873261058Smav	mrep->m_data += sizeof(uint32_t);
874261058Smav
875261058Smav	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
876261058Smav
877261058Smav	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
878261058Smav	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
879261058Smav		if (!xdr_replymsg(&xdrs, msg))
880261058Smav			stat = FALSE;
881261058Smav		else
882261058Smav			xdrmbuf_append(&xdrs, m);
883261058Smav	} else {
884261058Smav		stat = xdr_replymsg(&xdrs, msg);
885261058Smav	}
886261058Smav
887261058Smav	if (stat) {
888261058Smav		m_fixhdr(mrep);
889261058Smav
890261058Smav		/*
891261058Smav		 * Prepend a record marker containing the reply length.
892261058Smav		 */
893261058Smav		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
894261058Smav		*mtod(mrep, uint32_t *) =
895261058Smav			htonl(0x80000000 | (mrep->m_pkthdr.len
896261058Smav				- sizeof(uint32_t)));
897261058Smav		sx_xlock(&xprt->xp_lock);
898261058Smav		ct = (struct ct_data *)xprt->xp_p2;
899261058Smav		if (ct != NULL)
900261058Smav			error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
901261058Smav			    0, curthread);
902261058Smav		else
903261058Smav			error = EPIPE;
904261058Smav		sx_xunlock(&xprt->xp_lock);
905261058Smav		if (!error) {
906261058Smav			stat = TRUE;
907261058Smav		}
908261058Smav	} else {
909261058Smav		m_freem(mrep);
910261058Smav	}
911261058Smav
912261058Smav	XDR_DESTROY(&xdrs);
913261058Smav
914261058Smav	return (stat);
915261058Smav}
916261058Smav
917261058Smavstatic bool_t
918177633Sdfrsvc_vc_null()
919177633Sdfr{
920177633Sdfr
921177633Sdfr	return (FALSE);
922177633Sdfr}
923177633Sdfr
924193272Sjhbstatic int
925177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag)
926177633Sdfr{
927177633Sdfr	SVCXPRT *xprt = (SVCXPRT *) arg;
928177633Sdfr
929261059Smav	if (soreadable(xprt->xp_socket))
930261059Smav		xprt_active(xprt);
931193272Sjhb	return (SU_OK);
932177633Sdfr}
933177633Sdfr
934177633Sdfr#if 0
935177633Sdfr/*
936177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv
937177633Sdfr * and rpc.yppasswdd on AF_LOCAL.
938177633Sdfr */
939177633Sdfrint
940177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
941177633Sdfr	int sock, ret;
942177633Sdfr	gid_t egid;
943177633Sdfr	uid_t euid;
944177633Sdfr	struct sockaddr *sa;
945177633Sdfr
946177633Sdfr	sock = transp->xp_fd;
947184588Sdfr	sa = (struct sockaddr *)transp->xp_rtaddr;
948177633Sdfr	if (sa->sa_family == AF_LOCAL) {
949177633Sdfr		ret = getpeereid(sock, &euid, &egid);
950177633Sdfr		if (ret == 0)
951177633Sdfr			*uid = euid;
952177633Sdfr		return (ret);
953177633Sdfr	} else
954177633Sdfr		return (-1);
955177633Sdfr}
956177633Sdfr#endif
957