svc_vc.c revision 261053
1177633Sdfr/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
2177633Sdfr
3261046Smav/*-
4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261046Smav * All rights reserved.
6261046Smav *
7261046Smav * Redistribution and use in source and binary forms, with or without
8261046Smav * modification, are permitted provided that the following conditions are met:
9261046Smav * - Redistributions of source code must retain the above copyright notice,
10261046Smav *   this list of conditions and the following disclaimer.
11261046Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261046Smav *   this list of conditions and the following disclaimer in the documentation
13261046Smav *   and/or other materials provided with the distribution.
14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261046Smav *   contributors may be used to endorse or promote products derived
16261046Smav *   from this software without specific prior written permission.
17177633Sdfr *
18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261046Smav * 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: stable/10/sys/rpc/svc_vc.c 261053 2014-01-22 23:51:12Z mav $");
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>
47177633Sdfr#include <sys/lock.h>
48177633Sdfr#include <sys/kernel.h>
49177633Sdfr#include <sys/malloc.h>
50177633Sdfr#include <sys/mbuf.h>
51177633Sdfr#include <sys/mutex.h>
52193509Srwatson#include <sys/proc.h>
53177633Sdfr#include <sys/protosw.h>
54177633Sdfr#include <sys/queue.h>
55177633Sdfr#include <sys/socket.h>
56177633Sdfr#include <sys/socketvar.h>
57184588Sdfr#include <sys/sx.h>
58177633Sdfr#include <sys/systm.h>
59177633Sdfr#include <sys/uio.h>
60196503Szec
61196503Szec#include <net/vnet.h>
62196503Szec
63177633Sdfr#include <netinet/tcp.h>
64177633Sdfr
65177633Sdfr#include <rpc/rpc.h>
66177633Sdfr
67244008Srmacklem#include <rpc/krpc.h>
68177685Sdfr#include <rpc/rpc_com.h>
69177633Sdfr
70193509Srwatson#include <security/mac/mac_framework.h>
71193509Srwatson
72184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
73184588Sdfr    struct sockaddr **, struct mbuf **);
74177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
75177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *);
76177633Sdfrstatic bool_t svc_vc_null(void);
77177633Sdfrstatic void svc_vc_destroy(SVCXPRT *);
78177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *);
79184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
80184588Sdfr    struct sockaddr **, struct mbuf **);
81184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
82184588Sdfr    struct sockaddr *, struct mbuf *);
83177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
84177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
85177633Sdfr    void *in);
86244008Srmacklemstatic void svc_vc_backchannel_destroy(SVCXPRT *);
87244008Srmacklemstatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
88244008Srmacklemstatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
89244008Srmacklem    struct sockaddr **, struct mbuf **);
90244008Srmacklemstatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
91244008Srmacklem    struct sockaddr *, struct mbuf *);
92244008Srmacklemstatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
93244008Srmacklem    void *in);
94177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
95177633Sdfr    struct sockaddr *raddr);
96177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop);
97193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
98177633Sdfr
99177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = {
100177633Sdfr	.xp_recv =	svc_vc_rendezvous_recv,
101177633Sdfr	.xp_stat =	svc_vc_rendezvous_stat,
102184588Sdfr	.xp_reply =	(bool_t (*)(SVCXPRT *, struct rpc_msg *,
103184588Sdfr		struct sockaddr *, struct mbuf *))svc_vc_null,
104177633Sdfr	.xp_destroy =	svc_vc_rendezvous_destroy,
105177633Sdfr	.xp_control =	svc_vc_rendezvous_control
106177633Sdfr};
107177633Sdfr
108177633Sdfrstatic struct xp_ops svc_vc_ops = {
109177633Sdfr	.xp_recv =	svc_vc_recv,
110177633Sdfr	.xp_stat =	svc_vc_stat,
111177633Sdfr	.xp_reply =	svc_vc_reply,
112177633Sdfr	.xp_destroy =	svc_vc_destroy,
113177633Sdfr	.xp_control =	svc_vc_control
114177633Sdfr};
115177633Sdfr
116244008Srmacklemstatic struct xp_ops svc_vc_backchannel_ops = {
117244008Srmacklem	.xp_recv =	svc_vc_backchannel_recv,
118244008Srmacklem	.xp_stat =	svc_vc_backchannel_stat,
119244008Srmacklem	.xp_reply =	svc_vc_backchannel_reply,
120244008Srmacklem	.xp_destroy =	svc_vc_backchannel_destroy,
121244008Srmacklem	.xp_control =	svc_vc_backchannel_control
122177633Sdfr};
123177633Sdfr
124177633Sdfr/*
125177633Sdfr * Usage:
126177633Sdfr *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
127177633Sdfr *
128177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter.
129177633Sdfr * Once *xprt is initialized, it is registered as a transporter
130177633Sdfr * see (svc.h, xprt_register).  This routine returns
131177633Sdfr * a NULL if a problem occurred.
132177633Sdfr *
133177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but
134177633Sdfr * not yet connected socket.
135177633Sdfr *
136177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify
137177633Sdfr * how big the send and receive buffers are via the second and third parms;
138177633Sdfr * 0 => use the system default.
139177633Sdfr */
140177633SdfrSVCXPRT *
141177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
142177633Sdfr    size_t recvsize)
143177633Sdfr{
144177633Sdfr	SVCXPRT *xprt;
145177633Sdfr	struct sockaddr* sa;
146177633Sdfr	int error;
147177633Sdfr
148249263Sjhb	SOCK_LOCK(so);
149249263Sjhb	if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) {
150249263Sjhb		SOCK_UNLOCK(so);
151180025Sdfr		error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
152180025Sdfr		if (error)
153180025Sdfr			return (NULL);
154180025Sdfr		xprt = svc_vc_create_conn(pool, so, sa);
155180025Sdfr		free(sa, M_SONAME);
156180025Sdfr		return (xprt);
157180025Sdfr	}
158249263Sjhb	SOCK_UNLOCK(so);
159180025Sdfr
160184588Sdfr	xprt = svc_xprt_alloc();
161184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
162177633Sdfr	xprt->xp_pool = pool;
163177633Sdfr	xprt->xp_socket = so;
164177633Sdfr	xprt->xp_p1 = NULL;
165177633Sdfr	xprt->xp_p2 = NULL;
166177633Sdfr	xprt->xp_ops = &svc_vc_rendezvous_ops;
167177633Sdfr
168177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
169196503Szec	if (error) {
170177633Sdfr		goto cleanup_svc_vc_create;
171196503Szec	}
172177633Sdfr
173184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
174177633Sdfr	free(sa, M_SONAME);
175177633Sdfr
176177633Sdfr	xprt_register(xprt);
177177633Sdfr
178177633Sdfr	solisten(so, SOMAXCONN, curthread);
179177633Sdfr
180177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
181193436Srmacklem	xprt->xp_upcallset = 1;
182193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
183177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
184177633Sdfr
185177633Sdfr	return (xprt);
186177633Sdfrcleanup_svc_vc_create:
187177633Sdfr	if (xprt)
188184588Sdfr		svc_xprt_free(xprt);
189177633Sdfr	return (NULL);
190177633Sdfr}
191177633Sdfr
192177633Sdfr/*
193177633Sdfr * Create a new transport for a socket optained via soaccept().
194177633Sdfr */
195177633SdfrSVCXPRT *
196177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
197177633Sdfr{
198177633Sdfr	SVCXPRT *xprt = NULL;
199177633Sdfr	struct cf_conn *cd = NULL;
200177633Sdfr	struct sockaddr* sa = NULL;
201180025Sdfr	struct sockopt opt;
202180025Sdfr	int one = 1;
203177633Sdfr	int error;
204177633Sdfr
205180025Sdfr	bzero(&opt, sizeof(struct sockopt));
206180025Sdfr	opt.sopt_dir = SOPT_SET;
207180025Sdfr	opt.sopt_level = SOL_SOCKET;
208180025Sdfr	opt.sopt_name = SO_KEEPALIVE;
209180025Sdfr	opt.sopt_val = &one;
210180025Sdfr	opt.sopt_valsize = sizeof(one);
211180025Sdfr	error = sosetopt(so, &opt);
212196503Szec	if (error) {
213180025Sdfr		return (NULL);
214196503Szec	}
215180025Sdfr
216180025Sdfr	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
217180025Sdfr		bzero(&opt, sizeof(struct sockopt));
218180025Sdfr		opt.sopt_dir = SOPT_SET;
219180025Sdfr		opt.sopt_level = IPPROTO_TCP;
220180025Sdfr		opt.sopt_name = TCP_NODELAY;
221180025Sdfr		opt.sopt_val = &one;
222180025Sdfr		opt.sopt_valsize = sizeof(one);
223180025Sdfr		error = sosetopt(so, &opt);
224196503Szec		if (error) {
225180025Sdfr			return (NULL);
226196503Szec		}
227180025Sdfr	}
228180025Sdfr
229177633Sdfr	cd = mem_alloc(sizeof(*cd));
230177633Sdfr	cd->strm_stat = XPRT_IDLE;
231177633Sdfr
232184588Sdfr	xprt = svc_xprt_alloc();
233184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
234177633Sdfr	xprt->xp_pool = pool;
235177633Sdfr	xprt->xp_socket = so;
236177633Sdfr	xprt->xp_p1 = cd;
237177633Sdfr	xprt->xp_p2 = NULL;
238177633Sdfr	xprt->xp_ops = &svc_vc_ops;
239177633Sdfr
240184588Sdfr	/*
241184588Sdfr	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
242184588Sdfr	 * has a 5 minute timer, server has a 6 minute timer.
243184588Sdfr	 */
244184588Sdfr	xprt->xp_idletimeout = 6 * 60;
245177633Sdfr
246184588Sdfr	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
247184588Sdfr
248177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
249177633Sdfr	if (error)
250177633Sdfr		goto cleanup_svc_vc_create;
251177633Sdfr
252184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
253177633Sdfr	free(sa, M_SONAME);
254177633Sdfr
255177633Sdfr	xprt_register(xprt);
256177633Sdfr
257177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
258193436Srmacklem	xprt->xp_upcallset = 1;
259193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
260177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
261177633Sdfr
262177633Sdfr	/*
263177633Sdfr	 * Throw the transport into the active list in case it already
264177633Sdfr	 * has some data buffered.
265177633Sdfr	 */
266184588Sdfr	sx_xlock(&xprt->xp_lock);
267177633Sdfr	xprt_active(xprt);
268184588Sdfr	sx_xunlock(&xprt->xp_lock);
269177633Sdfr
270177633Sdfr	return (xprt);
271177633Sdfrcleanup_svc_vc_create:
272177633Sdfr	if (xprt) {
273177633Sdfr		mem_free(xprt, sizeof(*xprt));
274177633Sdfr	}
275177633Sdfr	if (cd)
276177633Sdfr		mem_free(cd, sizeof(*cd));
277177633Sdfr	return (NULL);
278177633Sdfr}
279177633Sdfr
280177633Sdfr/*
281244008Srmacklem * Create a new transport for a backchannel on a clnt_vc socket.
282244008Srmacklem */
283244008SrmacklemSVCXPRT *
284244008Srmacklemsvc_vc_create_backchannel(SVCPOOL *pool)
285244008Srmacklem{
286244008Srmacklem	SVCXPRT *xprt = NULL;
287244008Srmacklem	struct cf_conn *cd = NULL;
288244008Srmacklem
289244008Srmacklem	cd = mem_alloc(sizeof(*cd));
290244008Srmacklem	cd->strm_stat = XPRT_IDLE;
291244008Srmacklem
292244008Srmacklem	xprt = svc_xprt_alloc();
293244008Srmacklem	sx_init(&xprt->xp_lock, "xprt->xp_lock");
294244008Srmacklem	xprt->xp_pool = pool;
295244008Srmacklem	xprt->xp_socket = NULL;
296244008Srmacklem	xprt->xp_p1 = cd;
297244008Srmacklem	xprt->xp_p2 = NULL;
298244008Srmacklem	xprt->xp_ops = &svc_vc_backchannel_ops;
299244008Srmacklem	return (xprt);
300244008Srmacklem}
301244008Srmacklem
302244008Srmacklem/*
303177633Sdfr * This does all of the accept except the final call to soaccept. The
304177633Sdfr * caller will call soaccept after dropping its locks (soaccept may
305177633Sdfr * call malloc).
306177633Sdfr */
307177633Sdfrint
308177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop)
309177633Sdfr{
310177633Sdfr	int error = 0;
311177633Sdfr	struct socket *so;
312177633Sdfr
313177633Sdfr	if ((head->so_options & SO_ACCEPTCONN) == 0) {
314177633Sdfr		error = EINVAL;
315177633Sdfr		goto done;
316177633Sdfr	}
317177633Sdfr#ifdef MAC
318193509Srwatson	error = mac_socket_check_accept(curthread->td_ucred, head);
319177633Sdfr	if (error != 0)
320177633Sdfr		goto done;
321177633Sdfr#endif
322177633Sdfr	ACCEPT_LOCK();
323177633Sdfr	if (TAILQ_EMPTY(&head->so_comp)) {
324177633Sdfr		ACCEPT_UNLOCK();
325177633Sdfr		error = EWOULDBLOCK;
326177633Sdfr		goto done;
327177633Sdfr	}
328177633Sdfr	so = TAILQ_FIRST(&head->so_comp);
329177633Sdfr	KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
330177633Sdfr	KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
331177633Sdfr
332177633Sdfr	/*
333177633Sdfr	 * Before changing the flags on the socket, we have to bump the
334177633Sdfr	 * reference count.  Otherwise, if the protocol calls sofree(),
335177633Sdfr	 * the socket will be released due to a zero refcount.
336177633Sdfr	 * XXX might not need soref() since this is simpler than kern_accept.
337177633Sdfr	 */
338177633Sdfr	SOCK_LOCK(so);			/* soref() and so_state update */
339177633Sdfr	soref(so);			/* file descriptor reference */
340177633Sdfr
341177633Sdfr	TAILQ_REMOVE(&head->so_comp, so, so_list);
342177633Sdfr	head->so_qlen--;
343177633Sdfr	so->so_state |= (head->so_state & SS_NBIO);
344177633Sdfr	so->so_qstate &= ~SQ_COMP;
345177633Sdfr	so->so_head = NULL;
346177633Sdfr
347177633Sdfr	SOCK_UNLOCK(so);
348177633Sdfr	ACCEPT_UNLOCK();
349177633Sdfr
350177633Sdfr	*sop = so;
351177633Sdfr
352177633Sdfr	/* connection has been removed from the listen queue */
353177633Sdfr	KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
354177633Sdfrdone:
355177633Sdfr	return (error);
356177633Sdfr}
357177633Sdfr
358177633Sdfr/*ARGSUSED*/
359177633Sdfrstatic bool_t
360184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
361184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
362177633Sdfr{
363177633Sdfr	struct socket *so = NULL;
364177633Sdfr	struct sockaddr *sa = NULL;
365177633Sdfr	int error;
366194407Srmacklem	SVCXPRT *new_xprt;
367177633Sdfr
368177633Sdfr	/*
369177633Sdfr	 * The socket upcall calls xprt_active() which will eventually
370177633Sdfr	 * cause the server to call us here. We attempt to accept a
371177633Sdfr	 * connection from the socket and turn it into a new
372177633Sdfr	 * transport. If the accept fails, we have drained all pending
373177633Sdfr	 * connections so we call xprt_inactive().
374177633Sdfr	 */
375184588Sdfr	sx_xlock(&xprt->xp_lock);
376177633Sdfr
377177633Sdfr	error = svc_vc_accept(xprt->xp_socket, &so);
378177633Sdfr
379177633Sdfr	if (error == EWOULDBLOCK) {
380184588Sdfr		/*
381184588Sdfr		 * We must re-test for new connections after taking
382184588Sdfr		 * the lock to protect us in the case where a new
383184588Sdfr		 * connection arrives after our call to accept fails
384261047Smav		 * with EWOULDBLOCK.
385184588Sdfr		 */
386184588Sdfr		ACCEPT_LOCK();
387184588Sdfr		if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
388261053Smav			xprt_inactive_self(xprt);
389184588Sdfr		ACCEPT_UNLOCK();
390184588Sdfr		sx_xunlock(&xprt->xp_lock);
391177633Sdfr		return (FALSE);
392177633Sdfr	}
393177633Sdfr
394177633Sdfr	if (error) {
395177633Sdfr		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
396193436Srmacklem		if (xprt->xp_upcallset) {
397193436Srmacklem			xprt->xp_upcallset = 0;
398193436Srmacklem			soupcall_clear(xprt->xp_socket, SO_RCV);
399193436Srmacklem		}
400177633Sdfr		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
401261053Smav		xprt_inactive_self(xprt);
402184588Sdfr		sx_xunlock(&xprt->xp_lock);
403177633Sdfr		return (FALSE);
404177633Sdfr	}
405177633Sdfr
406184588Sdfr	sx_xunlock(&xprt->xp_lock);
407177633Sdfr
408177633Sdfr	sa = 0;
409177633Sdfr	error = soaccept(so, &sa);
410177633Sdfr
411177633Sdfr	if (error) {
412177633Sdfr		/*
413177633Sdfr		 * XXX not sure if I need to call sofree or soclose here.
414177633Sdfr		 */
415177633Sdfr		if (sa)
416177633Sdfr			free(sa, M_SONAME);
417177633Sdfr		return (FALSE);
418177633Sdfr	}
419177633Sdfr
420177633Sdfr	/*
421177633Sdfr	 * svc_vc_create_conn will call xprt_register - we don't need
422194407Srmacklem	 * to do anything with the new connection except derefence it.
423177633Sdfr	 */
424194407Srmacklem	new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
425194407Srmacklem	if (!new_xprt) {
426180025Sdfr		soclose(so);
427194407Srmacklem	} else {
428194407Srmacklem		SVC_RELEASE(new_xprt);
429194407Srmacklem	}
430180025Sdfr
431177633Sdfr	free(sa, M_SONAME);
432177633Sdfr
433177633Sdfr	return (FALSE); /* there is never an rpc msg to be processed */
434177633Sdfr}
435177633Sdfr
436177633Sdfr/*ARGSUSED*/
437177633Sdfrstatic enum xprt_stat
438177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt)
439177633Sdfr{
440177633Sdfr
441177633Sdfr	return (XPRT_IDLE);
442177633Sdfr}
443177633Sdfr
444177633Sdfrstatic void
445177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt)
446177633Sdfr{
447177633Sdfr	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
448193436Srmacklem	if (xprt->xp_upcallset) {
449193436Srmacklem		xprt->xp_upcallset = 0;
450193436Srmacklem		soupcall_clear(xprt->xp_socket, SO_RCV);
451193436Srmacklem	}
452177633Sdfr	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
453177633Sdfr
454184588Sdfr	sx_destroy(&xprt->xp_lock);
455177633Sdfr	if (xprt->xp_socket)
456177633Sdfr		(void)soclose(xprt->xp_socket);
457177633Sdfr
458184588Sdfr	if (xprt->xp_netid)
459184588Sdfr		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
460184588Sdfr	svc_xprt_free(xprt);
461177633Sdfr}
462177633Sdfr
463177633Sdfrstatic void
464177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt)
465177633Sdfr{
466177633Sdfr
467177633Sdfr	svc_vc_destroy_common(xprt);
468177633Sdfr}
469177633Sdfr
470177633Sdfrstatic void
471177633Sdfrsvc_vc_destroy(SVCXPRT *xprt)
472177633Sdfr{
473177633Sdfr	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
474177633Sdfr
475177633Sdfr	svc_vc_destroy_common(xprt);
476177633Sdfr
477177633Sdfr	if (cd->mreq)
478177633Sdfr		m_freem(cd->mreq);
479177633Sdfr	if (cd->mpending)
480177633Sdfr		m_freem(cd->mpending);
481177633Sdfr	mem_free(cd, sizeof(*cd));
482177633Sdfr}
483177633Sdfr
484244008Srmacklemstatic void
485244008Srmacklemsvc_vc_backchannel_destroy(SVCXPRT *xprt)
486244008Srmacklem{
487244008Srmacklem	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
488244008Srmacklem	struct mbuf *m, *m2;
489244008Srmacklem
490244008Srmacklem	svc_xprt_free(xprt);
491244008Srmacklem	m = cd->mreq;
492244008Srmacklem	while (m != NULL) {
493244008Srmacklem		m2 = m;
494244008Srmacklem		m = m->m_nextpkt;
495244008Srmacklem		m_freem(m2);
496244008Srmacklem	}
497244008Srmacklem	mem_free(cd, sizeof(*cd));
498244008Srmacklem}
499244008Srmacklem
500177633Sdfr/*ARGSUSED*/
501177633Sdfrstatic bool_t
502177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
503177633Sdfr{
504177633Sdfr	return (FALSE);
505177633Sdfr}
506177633Sdfr
507177633Sdfrstatic bool_t
508177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
509177633Sdfr{
510177633Sdfr
511177633Sdfr	return (FALSE);
512177633Sdfr}
513177633Sdfr
514244008Srmacklemstatic bool_t
515244008Srmacklemsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
516244008Srmacklem{
517244008Srmacklem
518244008Srmacklem	return (FALSE);
519244008Srmacklem}
520244008Srmacklem
521177633Sdfrstatic enum xprt_stat
522177633Sdfrsvc_vc_stat(SVCXPRT *xprt)
523177633Sdfr{
524177633Sdfr	struct cf_conn *cd;
525177633Sdfr
526177633Sdfr	cd = (struct cf_conn *)(xprt->xp_p1);
527177633Sdfr
528177633Sdfr	if (cd->strm_stat == XPRT_DIED)
529177633Sdfr		return (XPRT_DIED);
530177633Sdfr
531261047Smav	if (cd->mreq != NULL && cd->resid == 0 && cd->eor)
532261047Smav		return (XPRT_MOREREQS);
533177633Sdfr
534184588Sdfr	if (soreadable(xprt->xp_socket))
535184588Sdfr		return (XPRT_MOREREQS);
536184588Sdfr
537177633Sdfr	return (XPRT_IDLE);
538177633Sdfr}
539177633Sdfr
540244008Srmacklemstatic enum xprt_stat
541244008Srmacklemsvc_vc_backchannel_stat(SVCXPRT *xprt)
542244008Srmacklem{
543244008Srmacklem	struct cf_conn *cd;
544244008Srmacklem
545244008Srmacklem	cd = (struct cf_conn *)(xprt->xp_p1);
546244008Srmacklem
547244008Srmacklem	if (cd->mreq != NULL)
548244008Srmacklem		return (XPRT_MOREREQS);
549244008Srmacklem
550244008Srmacklem	return (XPRT_IDLE);
551244008Srmacklem}
552244008Srmacklem
553261047Smav/*
554261047Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it,
555261047Smav * leaving the result in cd->mreq. If we don't have a complete record, leave
556261047Smav * the partial result in cd->mreq and try to read more from the socket.
557261047Smav */
558261050Smavstatic int
559261047Smavsvc_vc_process_pending(SVCXPRT *xprt)
560261047Smav{
561261047Smav	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
562261047Smav	struct socket *so = xprt->xp_socket;
563261047Smav	struct mbuf *m;
564261047Smav
565261047Smav	/*
566261047Smav	 * If cd->resid is non-zero, we have part of the
567261047Smav	 * record already, otherwise we are expecting a record
568261047Smav	 * marker.
569261047Smav	 */
570261047Smav	if (!cd->resid && cd->mpending) {
571261047Smav		/*
572261047Smav		 * See if there is enough data buffered to
573261047Smav		 * make up a record marker. Make sure we can
574261047Smav		 * handle the case where the record marker is
575261047Smav		 * split across more than one mbuf.
576261047Smav		 */
577261047Smav		size_t n = 0;
578261047Smav		uint32_t header;
579261047Smav
580261047Smav		m = cd->mpending;
581261047Smav		while (n < sizeof(uint32_t) && m) {
582261047Smav			n += m->m_len;
583261047Smav			m = m->m_next;
584261047Smav		}
585261047Smav		if (n < sizeof(uint32_t)) {
586261047Smav			so->so_rcv.sb_lowat = sizeof(uint32_t) - n;
587261050Smav			return (FALSE);
588261047Smav		}
589261047Smav		m_copydata(cd->mpending, 0, sizeof(header),
590261047Smav		    (char *)&header);
591261047Smav		header = ntohl(header);
592261047Smav		cd->eor = (header & 0x80000000) != 0;
593261047Smav		cd->resid = header & 0x7fffffff;
594261047Smav		m_adj(cd->mpending, sizeof(uint32_t));
595261047Smav	}
596261047Smav
597261047Smav	/*
598261047Smav	 * Start pulling off mbufs from cd->mpending
599261047Smav	 * until we either have a complete record or
600261047Smav	 * we run out of data. We use m_split to pull
601261047Smav	 * data - it will pull as much as possible and
602261047Smav	 * split the last mbuf if necessary.
603261047Smav	 */
604261047Smav	while (cd->mpending && cd->resid) {
605261047Smav		m = cd->mpending;
606261047Smav		if (cd->mpending->m_next
607261047Smav		    || cd->mpending->m_len > cd->resid)
608261047Smav			cd->mpending = m_split(cd->mpending,
609261047Smav			    cd->resid, M_WAITOK);
610261047Smav		else
611261047Smav			cd->mpending = NULL;
612261047Smav		if (cd->mreq)
613261047Smav			m_last(cd->mreq)->m_next = m;
614261047Smav		else
615261047Smav			cd->mreq = m;
616261047Smav		while (m) {
617261047Smav			cd->resid -= m->m_len;
618261047Smav			m = m->m_next;
619261047Smav		}
620261047Smav	}
621261047Smav
622261052Smav	/*
623261052Smav	 * Block receive upcalls if we have more data pending,
624261052Smav	 * otherwise report our need.
625261052Smav	 */
626261052Smav	if (cd->mpending)
627261052Smav		so->so_rcv.sb_lowat = INT_MAX;
628261052Smav	else
629261052Smav		so->so_rcv.sb_lowat =
630261052Smav		    imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2));
631261050Smav	return (TRUE);
632261047Smav}
633261047Smav
634177633Sdfrstatic bool_t
635184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
636184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
637177633Sdfr{
638177633Sdfr	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
639177633Sdfr	struct uio uio;
640177633Sdfr	struct mbuf *m;
641261047Smav	struct socket* so = xprt->xp_socket;
642184588Sdfr	XDR xdrs;
643177633Sdfr	int error, rcvflag;
644177633Sdfr
645184588Sdfr	/*
646184588Sdfr	 * Serialise access to the socket and our own record parsing
647184588Sdfr	 * state.
648184588Sdfr	 */
649184588Sdfr	sx_xlock(&xprt->xp_lock);
650184588Sdfr
651177633Sdfr	for (;;) {
652261047Smav		/* If we have no request ready, check pending queue. */
653261047Smav		while (cd->mpending &&
654261050Smav		    (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) {
655261050Smav			if (!svc_vc_process_pending(xprt))
656261050Smav				break;
657261050Smav		}
658177633Sdfr
659261047Smav		/* Process and return complete request in cd->mreq. */
660261047Smav		if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
661177633Sdfr
662261047Smav			xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
663261047Smav			cd->mreq = NULL;
664261047Smav
665261047Smav			/* Check for next request in a pending queue. */
666261047Smav			svc_vc_process_pending(xprt);
667261047Smav			if (cd->mreq == NULL || cd->resid != 0) {
668261047Smav				SOCKBUF_LOCK(&so->so_rcv);
669261047Smav				if (!soreadable(so))
670261053Smav					xprt_inactive_self(xprt);
671261047Smav				SOCKBUF_UNLOCK(&so->so_rcv);
672177633Sdfr			}
673177633Sdfr
674261047Smav			sx_xunlock(&xprt->xp_lock);
675177633Sdfr
676261047Smav			if (! xdr_callmsg(&xdrs, msg)) {
677261047Smav				XDR_DESTROY(&xdrs);
678261047Smav				return (FALSE);
679261047Smav			}
680184588Sdfr
681261047Smav			*addrp = NULL;
682261047Smav			*mp = xdrmbuf_getall(&xdrs);
683261047Smav			XDR_DESTROY(&xdrs);
684177633Sdfr
685261047Smav			return (TRUE);
686177633Sdfr		}
687177633Sdfr
688177633Sdfr		/*
689177633Sdfr		 * The socket upcall calls xprt_active() which will eventually
690177633Sdfr		 * cause the server to call us here. We attempt to
691177633Sdfr		 * read as much as possible from the socket and put
692177633Sdfr		 * the result in cd->mpending. If the read fails,
693177633Sdfr		 * we have drained both cd->mpending and the socket so
694177633Sdfr		 * we can call xprt_inactive().
695177633Sdfr		 */
696177633Sdfr		uio.uio_resid = 1000000000;
697177633Sdfr		uio.uio_td = curthread;
698177633Sdfr		m = NULL;
699177633Sdfr		rcvflag = MSG_DONTWAIT;
700261047Smav		error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
701177633Sdfr
702177633Sdfr		if (error == EWOULDBLOCK) {
703184588Sdfr			/*
704184588Sdfr			 * We must re-test for readability after
705184588Sdfr			 * taking the lock to protect us in the case
706184588Sdfr			 * where a new packet arrives on the socket
707184588Sdfr			 * after our call to soreceive fails with
708261047Smav			 * EWOULDBLOCK.
709184588Sdfr			 */
710261047Smav			SOCKBUF_LOCK(&so->so_rcv);
711261047Smav			if (!soreadable(so))
712261053Smav				xprt_inactive_self(xprt);
713261047Smav			SOCKBUF_UNLOCK(&so->so_rcv);
714184588Sdfr			sx_xunlock(&xprt->xp_lock);
715177633Sdfr			return (FALSE);
716177633Sdfr		}
717177633Sdfr
718177633Sdfr		if (error) {
719261047Smav			SOCKBUF_LOCK(&so->so_rcv);
720193436Srmacklem			if (xprt->xp_upcallset) {
721193436Srmacklem				xprt->xp_upcallset = 0;
722261047Smav				soupcall_clear(so, SO_RCV);
723193436Srmacklem			}
724261047Smav			SOCKBUF_UNLOCK(&so->so_rcv);
725261053Smav			xprt_inactive_self(xprt);
726177633Sdfr			cd->strm_stat = XPRT_DIED;
727184588Sdfr			sx_xunlock(&xprt->xp_lock);
728177633Sdfr			return (FALSE);
729177633Sdfr		}
730177633Sdfr
731177633Sdfr		if (!m) {
732177633Sdfr			/*
733177633Sdfr			 * EOF - the other end has closed the socket.
734177633Sdfr			 */
735261053Smav			xprt_inactive_self(xprt);
736177633Sdfr			cd->strm_stat = XPRT_DIED;
737184588Sdfr			sx_xunlock(&xprt->xp_lock);
738177633Sdfr			return (FALSE);
739177633Sdfr		}
740177633Sdfr
741177633Sdfr		if (cd->mpending)
742177633Sdfr			m_last(cd->mpending)->m_next = m;
743177633Sdfr		else
744177633Sdfr			cd->mpending = m;
745177633Sdfr	}
746177633Sdfr}
747177633Sdfr
748177633Sdfrstatic bool_t
749244008Srmacklemsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
750244008Srmacklem    struct sockaddr **addrp, struct mbuf **mp)
751244008Srmacklem{
752244008Srmacklem	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
753244008Srmacklem	struct ct_data *ct;
754244008Srmacklem	struct mbuf *m;
755244008Srmacklem	XDR xdrs;
756244008Srmacklem
757244008Srmacklem	sx_xlock(&xprt->xp_lock);
758244008Srmacklem	ct = (struct ct_data *)xprt->xp_p2;
759244008Srmacklem	if (ct == NULL) {
760244008Srmacklem		sx_xunlock(&xprt->xp_lock);
761244008Srmacklem		return (FALSE);
762244008Srmacklem	}
763244008Srmacklem	mtx_lock(&ct->ct_lock);
764244008Srmacklem	m = cd->mreq;
765244008Srmacklem	if (m == NULL) {
766261053Smav		xprt_inactive_self(xprt);
767244008Srmacklem		mtx_unlock(&ct->ct_lock);
768244008Srmacklem		sx_xunlock(&xprt->xp_lock);
769244008Srmacklem		return (FALSE);
770244008Srmacklem	}
771244008Srmacklem	cd->mreq = m->m_nextpkt;
772244008Srmacklem	mtx_unlock(&ct->ct_lock);
773244008Srmacklem	sx_xunlock(&xprt->xp_lock);
774244008Srmacklem
775244008Srmacklem	xdrmbuf_create(&xdrs, m, XDR_DECODE);
776244008Srmacklem	if (! xdr_callmsg(&xdrs, msg)) {
777244008Srmacklem		XDR_DESTROY(&xdrs);
778244008Srmacklem		return (FALSE);
779244008Srmacklem	}
780244008Srmacklem	*addrp = NULL;
781244008Srmacklem	*mp = xdrmbuf_getall(&xdrs);
782244008Srmacklem	XDR_DESTROY(&xdrs);
783244008Srmacklem	return (TRUE);
784244008Srmacklem}
785244008Srmacklem
786244008Srmacklemstatic bool_t
787184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
788184588Sdfr    struct sockaddr *addr, struct mbuf *m)
789177633Sdfr{
790177633Sdfr	XDR xdrs;
791177633Sdfr	struct mbuf *mrep;
792184588Sdfr	bool_t stat = TRUE;
793177633Sdfr	int error;
794177633Sdfr
795177633Sdfr	/*
796177633Sdfr	 * Leave space for record mark.
797177633Sdfr	 */
798248195Sglebius	mrep = m_gethdr(M_WAITOK, MT_DATA);
799177633Sdfr	mrep->m_data += sizeof(uint32_t);
800177633Sdfr
801184588Sdfr	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
802184588Sdfr
803184588Sdfr	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
804184588Sdfr	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
805184588Sdfr		if (!xdr_replymsg(&xdrs, msg))
806184588Sdfr			stat = FALSE;
807184588Sdfr		else
808184588Sdfr			xdrmbuf_append(&xdrs, m);
809184588Sdfr	} else {
810184588Sdfr		stat = xdr_replymsg(&xdrs, msg);
811184588Sdfr	}
812184588Sdfr
813184588Sdfr	if (stat) {
814177633Sdfr		m_fixhdr(mrep);
815177633Sdfr
816177633Sdfr		/*
817177633Sdfr		 * Prepend a record marker containing the reply length.
818177633Sdfr		 */
819243882Sglebius		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
820177633Sdfr		*mtod(mrep, uint32_t *) =
821177633Sdfr			htonl(0x80000000 | (mrep->m_pkthdr.len
822177633Sdfr				- sizeof(uint32_t)));
823177633Sdfr		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
824177633Sdfr		    0, curthread);
825177633Sdfr		if (!error) {
826177633Sdfr			stat = TRUE;
827177633Sdfr		}
828177633Sdfr	} else {
829177633Sdfr		m_freem(mrep);
830177633Sdfr	}
831177633Sdfr
832184588Sdfr	XDR_DESTROY(&xdrs);
833177633Sdfr	xprt->xp_p2 = NULL;
834177633Sdfr
835177633Sdfr	return (stat);
836177633Sdfr}
837177633Sdfr
838177633Sdfrstatic bool_t
839244008Srmacklemsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
840244008Srmacklem    struct sockaddr *addr, struct mbuf *m)
841244008Srmacklem{
842244008Srmacklem	struct ct_data *ct;
843244008Srmacklem	XDR xdrs;
844244008Srmacklem	struct mbuf *mrep;
845244008Srmacklem	bool_t stat = TRUE;
846244008Srmacklem	int error;
847244008Srmacklem
848244008Srmacklem	/*
849244008Srmacklem	 * Leave space for record mark.
850244008Srmacklem	 */
851248195Sglebius	mrep = m_gethdr(M_WAITOK, MT_DATA);
852244008Srmacklem	mrep->m_data += sizeof(uint32_t);
853244008Srmacklem
854244008Srmacklem	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
855244008Srmacklem
856244008Srmacklem	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
857244008Srmacklem	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
858244008Srmacklem		if (!xdr_replymsg(&xdrs, msg))
859244008Srmacklem			stat = FALSE;
860244008Srmacklem		else
861244008Srmacklem			xdrmbuf_append(&xdrs, m);
862244008Srmacklem	} else {
863244008Srmacklem		stat = xdr_replymsg(&xdrs, msg);
864244008Srmacklem	}
865244008Srmacklem
866244008Srmacklem	if (stat) {
867244008Srmacklem		m_fixhdr(mrep);
868244008Srmacklem
869244008Srmacklem		/*
870244008Srmacklem		 * Prepend a record marker containing the reply length.
871244008Srmacklem		 */
872244008Srmacklem		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
873244008Srmacklem		*mtod(mrep, uint32_t *) =
874244008Srmacklem			htonl(0x80000000 | (mrep->m_pkthdr.len
875244008Srmacklem				- sizeof(uint32_t)));
876244008Srmacklem		sx_xlock(&xprt->xp_lock);
877244008Srmacklem		ct = (struct ct_data *)xprt->xp_p2;
878244008Srmacklem		if (ct != NULL)
879244008Srmacklem			error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
880244008Srmacklem			    0, curthread);
881244008Srmacklem		else
882244008Srmacklem			error = EPIPE;
883244008Srmacklem		sx_xunlock(&xprt->xp_lock);
884244008Srmacklem		if (!error) {
885244008Srmacklem			stat = TRUE;
886244008Srmacklem		}
887244008Srmacklem	} else {
888244008Srmacklem		m_freem(mrep);
889244008Srmacklem	}
890244008Srmacklem
891244008Srmacklem	XDR_DESTROY(&xdrs);
892244008Srmacklem
893244008Srmacklem	return (stat);
894244008Srmacklem}
895244008Srmacklem
896244008Srmacklemstatic bool_t
897177633Sdfrsvc_vc_null()
898177633Sdfr{
899177633Sdfr
900177633Sdfr	return (FALSE);
901177633Sdfr}
902177633Sdfr
903193272Sjhbstatic int
904177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag)
905177633Sdfr{
906177633Sdfr	SVCXPRT *xprt = (SVCXPRT *) arg;
907177633Sdfr
908261047Smav	if (soreadable(xprt->xp_socket))
909261047Smav		xprt_active(xprt);
910193272Sjhb	return (SU_OK);
911177633Sdfr}
912177633Sdfr
913177633Sdfr#if 0
914177633Sdfr/*
915177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv
916177633Sdfr * and rpc.yppasswdd on AF_LOCAL.
917177633Sdfr */
918177633Sdfrint
919177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
920177633Sdfr	int sock, ret;
921177633Sdfr	gid_t egid;
922177633Sdfr	uid_t euid;
923177633Sdfr	struct sockaddr *sa;
924177633Sdfr
925177633Sdfr	sock = transp->xp_fd;
926184588Sdfr	sa = (struct sockaddr *)transp->xp_rtaddr;
927177633Sdfr	if (sa->sa_family == AF_LOCAL) {
928177633Sdfr		ret = getpeereid(sock, &euid, &egid);
929177633Sdfr		if (ret == 0)
930177633Sdfr			*uid = euid;
931177633Sdfr		return (ret);
932177633Sdfr	} else
933177633Sdfr		return (-1);
934177633Sdfr}
935177633Sdfr#endif
936