1c59e4cc3SRick Macklem /* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
2c59e4cc3SRick Macklem
3c59e4cc3SRick Macklem /*-
4c59e4cc3SRick Macklem * Copyright (c) 2009, Sun Microsystems, Inc.
5c59e4cc3SRick Macklem * All rights reserved.
6c59e4cc3SRick Macklem *
7c59e4cc3SRick Macklem * Redistribution and use in source and binary forms, with or without
8c59e4cc3SRick Macklem * modification, are permitted provided that the following conditions are met:
9c59e4cc3SRick Macklem * - Redistributions of source code must retain the above copyright notice,
10c59e4cc3SRick Macklem * this list of conditions and the following disclaimer.
11c59e4cc3SRick Macklem * - Redistributions in binary form must reproduce the above copyright notice,
12c59e4cc3SRick Macklem * this list of conditions and the following disclaimer in the documentation
13c59e4cc3SRick Macklem * and/or other materials provided with the distribution.
14c59e4cc3SRick Macklem * - Neither the name of Sun Microsystems, Inc. nor the names of its
15c59e4cc3SRick Macklem * contributors may be used to endorse or promote products derived
16c59e4cc3SRick Macklem * from this software without specific prior written permission.
17c59e4cc3SRick Macklem *
18c59e4cc3SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19c59e4cc3SRick Macklem * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20c59e4cc3SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21c59e4cc3SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22c59e4cc3SRick Macklem * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23c59e4cc3SRick Macklem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24c59e4cc3SRick Macklem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25c59e4cc3SRick Macklem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26c59e4cc3SRick Macklem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27c59e4cc3SRick Macklem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28c59e4cc3SRick Macklem * POSSIBILITY OF SUCH DAMAGE.
29c59e4cc3SRick Macklem */
30c59e4cc3SRick Macklem
31c59e4cc3SRick Macklem #include <sys/cdefs.h>
32c59e4cc3SRick Macklem /*
33c59e4cc3SRick Macklem * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
34c59e4cc3SRick Macklem *
35c59e4cc3SRick Macklem * Copyright (C) 1984, Sun Microsystems, Inc.
36c59e4cc3SRick Macklem *
37c59e4cc3SRick Macklem * TCP based RPC supports 'batched calls'.
38c59e4cc3SRick Macklem * A sequence of calls may be batched-up in a send buffer. The rpc call
39c59e4cc3SRick Macklem * return immediately to the client even though the call was not necessarily
40c59e4cc3SRick Macklem * sent. The batching occurs if the results' xdr routine is NULL (0) AND
41c59e4cc3SRick Macklem * the rpc timeout value is zero (see clnt.h, rpc).
42c59e4cc3SRick Macklem *
43c59e4cc3SRick Macklem * Clients should NOT casually batch calls that in fact return results; that is,
44c59e4cc3SRick Macklem * the server side should be aware that a call is batched and not produce any
45c59e4cc3SRick Macklem * return message. Batched calls that produce many result messages can
46c59e4cc3SRick Macklem * deadlock (netlock) the client and the server....
47c59e4cc3SRick Macklem *
48c59e4cc3SRick Macklem * Now go hang yourself.
49c59e4cc3SRick Macklem */
50c59e4cc3SRick Macklem
51c59e4cc3SRick Macklem /*
52c59e4cc3SRick Macklem * This code handles the special case of a NFSv4.n backchannel for
53c59e4cc3SRick Macklem * callback RPCs. It is similar to clnt_vc.c, but uses the TCP
54c59e4cc3SRick Macklem * connection provided by the client to the server.
55c59e4cc3SRick Macklem */
56c59e4cc3SRick Macklem
57ab0c29afSRick Macklem #include "opt_kern_tls.h"
58ab0c29afSRick Macklem
59c59e4cc3SRick Macklem #include <sys/param.h>
60c59e4cc3SRick Macklem #include <sys/systm.h>
61ab0c29afSRick Macklem #include <sys/ktls.h>
62c59e4cc3SRick Macklem #include <sys/lock.h>
63c59e4cc3SRick Macklem #include <sys/malloc.h>
64c59e4cc3SRick Macklem #include <sys/mbuf.h>
65c59e4cc3SRick Macklem #include <sys/mutex.h>
66c59e4cc3SRick Macklem #include <sys/pcpu.h>
67c59e4cc3SRick Macklem #include <sys/proc.h>
68c59e4cc3SRick Macklem #include <sys/protosw.h>
69c59e4cc3SRick Macklem #include <sys/socket.h>
70c59e4cc3SRick Macklem #include <sys/socketvar.h>
71c59e4cc3SRick Macklem #include <sys/sx.h>
72c59e4cc3SRick Macklem #include <sys/syslog.h>
73c59e4cc3SRick Macklem #include <sys/time.h>
74c59e4cc3SRick Macklem #include <sys/uio.h>
75c59e4cc3SRick Macklem
76c59e4cc3SRick Macklem #include <net/vnet.h>
77c59e4cc3SRick Macklem
78c59e4cc3SRick Macklem #include <netinet/tcp.h>
79c59e4cc3SRick Macklem
80c59e4cc3SRick Macklem #include <rpc/rpc.h>
81c59e4cc3SRick Macklem #include <rpc/rpc_com.h>
82c59e4cc3SRick Macklem #include <rpc/krpc.h>
83ab0c29afSRick Macklem #include <rpc/rpcsec_tls.h>
84c59e4cc3SRick Macklem
85c59e4cc3SRick Macklem struct cmessage {
86c59e4cc3SRick Macklem struct cmsghdr cmsg;
87c59e4cc3SRick Macklem struct cmsgcred cmcred;
88c59e4cc3SRick Macklem };
89c59e4cc3SRick Macklem
90c59e4cc3SRick Macklem static void clnt_bck_geterr(CLIENT *, struct rpc_err *);
91c59e4cc3SRick Macklem static bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *);
92c59e4cc3SRick Macklem static void clnt_bck_abort(CLIENT *);
93c59e4cc3SRick Macklem static bool_t clnt_bck_control(CLIENT *, u_int, void *);
94c59e4cc3SRick Macklem static void clnt_bck_close(CLIENT *);
95c59e4cc3SRick Macklem static void clnt_bck_destroy(CLIENT *);
96c59e4cc3SRick Macklem
9720d728b5SMark Johnston static const struct clnt_ops clnt_bck_ops = {
98c59e4cc3SRick Macklem .cl_abort = clnt_bck_abort,
99c59e4cc3SRick Macklem .cl_geterr = clnt_bck_geterr,
100c59e4cc3SRick Macklem .cl_freeres = clnt_bck_freeres,
101c59e4cc3SRick Macklem .cl_close = clnt_bck_close,
102c59e4cc3SRick Macklem .cl_destroy = clnt_bck_destroy,
103c59e4cc3SRick Macklem .cl_control = clnt_bck_control
104c59e4cc3SRick Macklem };
105c59e4cc3SRick Macklem
106c59e4cc3SRick Macklem /*
107c59e4cc3SRick Macklem * Create a client handle for a connection.
108c59e4cc3SRick Macklem * Default options are set, which the user can change using clnt_control()'s.
109c59e4cc3SRick Macklem * This code handles the special case of an NFSv4.1 session backchannel
110c59e4cc3SRick Macklem * call, which is sent on a TCP connection created against the server
111c59e4cc3SRick Macklem * by a client.
112c59e4cc3SRick Macklem */
113c59e4cc3SRick Macklem void *
clnt_bck_create(struct socket * so,const rpcprog_t prog,const rpcvers_t vers)114c59e4cc3SRick Macklem clnt_bck_create(
115c59e4cc3SRick Macklem struct socket *so, /* Server transport socket. */
116c59e4cc3SRick Macklem const rpcprog_t prog, /* program number */
117c59e4cc3SRick Macklem const rpcvers_t vers) /* version number */
118c59e4cc3SRick Macklem {
119c59e4cc3SRick Macklem CLIENT *cl; /* client handle */
120c59e4cc3SRick Macklem struct ct_data *ct = NULL; /* client handle */
121c59e4cc3SRick Macklem struct timeval now;
122c59e4cc3SRick Macklem struct rpc_msg call_msg;
123c59e4cc3SRick Macklem static uint32_t disrupt;
124c59e4cc3SRick Macklem XDR xdrs;
125c59e4cc3SRick Macklem
126c59e4cc3SRick Macklem if (disrupt == 0)
127c59e4cc3SRick Macklem disrupt = (uint32_t)(long)so;
128c59e4cc3SRick Macklem
129c59e4cc3SRick Macklem cl = (CLIENT *)mem_alloc(sizeof (*cl));
130c59e4cc3SRick Macklem ct = (struct ct_data *)mem_alloc(sizeof (*ct));
131c59e4cc3SRick Macklem
132c59e4cc3SRick Macklem mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
133c59e4cc3SRick Macklem ct->ct_threads = 0;
134c59e4cc3SRick Macklem ct->ct_closing = FALSE;
135c59e4cc3SRick Macklem ct->ct_closed = FALSE;
136c59e4cc3SRick Macklem ct->ct_upcallrefs = 0;
137c59e4cc3SRick Macklem ct->ct_closeit = FALSE;
138c59e4cc3SRick Macklem
139c59e4cc3SRick Macklem /*
140c59e4cc3SRick Macklem * Set up private data struct
141c59e4cc3SRick Macklem */
142c59e4cc3SRick Macklem ct->ct_wait.tv_sec = -1;
143c59e4cc3SRick Macklem ct->ct_wait.tv_usec = -1;
144c59e4cc3SRick Macklem
145c59e4cc3SRick Macklem /*
146c59e4cc3SRick Macklem * Initialize call message
147c59e4cc3SRick Macklem */
148c59e4cc3SRick Macklem getmicrotime(&now);
149c59e4cc3SRick Macklem ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
150c59e4cc3SRick Macklem call_msg.rm_xid = ct->ct_xid;
151c59e4cc3SRick Macklem call_msg.rm_direction = CALL;
152c59e4cc3SRick Macklem call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
153c59e4cc3SRick Macklem call_msg.rm_call.cb_prog = (uint32_t)prog;
154c59e4cc3SRick Macklem call_msg.rm_call.cb_vers = (uint32_t)vers;
155c59e4cc3SRick Macklem
156c59e4cc3SRick Macklem /*
157c59e4cc3SRick Macklem * pre-serialize the static part of the call msg and stash it away
158c59e4cc3SRick Macklem */
159c59e4cc3SRick Macklem xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
160c59e4cc3SRick Macklem XDR_ENCODE);
161c59e4cc3SRick Macklem if (!xdr_callhdr(&xdrs, &call_msg))
162c59e4cc3SRick Macklem goto err;
163c59e4cc3SRick Macklem ct->ct_mpos = XDR_GETPOS(&xdrs);
164c59e4cc3SRick Macklem XDR_DESTROY(&xdrs);
165c59e4cc3SRick Macklem ct->ct_waitchan = "rpcbck";
166c59e4cc3SRick Macklem ct->ct_waitflag = 0;
167c59e4cc3SRick Macklem cl->cl_refs = 1;
168c59e4cc3SRick Macklem cl->cl_ops = &clnt_bck_ops;
169c59e4cc3SRick Macklem cl->cl_private = ct;
170c59e4cc3SRick Macklem cl->cl_auth = authnone_create();
171c59e4cc3SRick Macklem TAILQ_INIT(&ct->ct_pending);
172c59e4cc3SRick Macklem return (cl);
173c59e4cc3SRick Macklem
174c59e4cc3SRick Macklem err:
175c59e4cc3SRick Macklem mtx_destroy(&ct->ct_lock);
176c59e4cc3SRick Macklem mem_free(ct, sizeof (struct ct_data));
177c59e4cc3SRick Macklem mem_free(cl, sizeof (CLIENT));
178c59e4cc3SRick Macklem return (NULL);
179c59e4cc3SRick Macklem }
180c59e4cc3SRick Macklem
181c59e4cc3SRick Macklem enum clnt_stat
clnt_bck_call(CLIENT * cl,struct rpc_callextra * ext,rpcproc_t proc,struct mbuf * args,struct mbuf ** resultsp,struct timeval utimeout,SVCXPRT * xprt)182c59e4cc3SRick Macklem clnt_bck_call(
183c59e4cc3SRick Macklem CLIENT *cl, /* client handle */
184c59e4cc3SRick Macklem struct rpc_callextra *ext, /* call metadata */
185c59e4cc3SRick Macklem rpcproc_t proc, /* procedure number */
186c59e4cc3SRick Macklem struct mbuf *args, /* pointer to args */
187c59e4cc3SRick Macklem struct mbuf **resultsp, /* pointer to results */
188c59e4cc3SRick Macklem struct timeval utimeout,
189c59e4cc3SRick Macklem SVCXPRT *xprt)
190c59e4cc3SRick Macklem {
191c59e4cc3SRick Macklem struct ct_data *ct = (struct ct_data *) cl->cl_private;
192c59e4cc3SRick Macklem AUTH *auth;
193c59e4cc3SRick Macklem struct rpc_err *errp;
194c59e4cc3SRick Macklem enum clnt_stat stat;
195c59e4cc3SRick Macklem XDR xdrs;
196c59e4cc3SRick Macklem struct rpc_msg reply_msg;
197c59e4cc3SRick Macklem bool_t ok;
198c59e4cc3SRick Macklem int nrefreshes = 2; /* number of times to refresh cred */
199c59e4cc3SRick Macklem struct timeval timeout;
200c59e4cc3SRick Macklem uint32_t xid;
201c59e4cc3SRick Macklem struct mbuf *mreq = NULL, *results;
202c59e4cc3SRick Macklem struct ct_request *cr;
203ab0c29afSRick Macklem int error, maxextsiz;
204ab0c29afSRick Macklem #ifdef KERN_TLS
205ab0c29afSRick Macklem u_int maxlen;
206ab0c29afSRick Macklem #endif
207c59e4cc3SRick Macklem
208c59e4cc3SRick Macklem cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
209c59e4cc3SRick Macklem
210c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
211c59e4cc3SRick Macklem
212c59e4cc3SRick Macklem if (ct->ct_closing || ct->ct_closed) {
213c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
214c59e4cc3SRick Macklem free(cr, M_RPC);
215c59e4cc3SRick Macklem return (RPC_CANTSEND);
216c59e4cc3SRick Macklem }
217c59e4cc3SRick Macklem ct->ct_threads++;
218c59e4cc3SRick Macklem
219c59e4cc3SRick Macklem if (ext) {
220c59e4cc3SRick Macklem auth = ext->rc_auth;
221c59e4cc3SRick Macklem errp = &ext->rc_err;
222c59e4cc3SRick Macklem } else {
223c59e4cc3SRick Macklem auth = cl->cl_auth;
224c59e4cc3SRick Macklem errp = &ct->ct_error;
225c59e4cc3SRick Macklem }
226c59e4cc3SRick Macklem
227c59e4cc3SRick Macklem cr->cr_mrep = NULL;
228c59e4cc3SRick Macklem cr->cr_error = 0;
229c59e4cc3SRick Macklem
230c59e4cc3SRick Macklem if (ct->ct_wait.tv_usec == -1)
231c59e4cc3SRick Macklem timeout = utimeout; /* use supplied timeout */
232c59e4cc3SRick Macklem else
233c59e4cc3SRick Macklem timeout = ct->ct_wait; /* use default timeout */
234c59e4cc3SRick Macklem
235c59e4cc3SRick Macklem call_again:
236c59e4cc3SRick Macklem mtx_assert(&ct->ct_lock, MA_OWNED);
237c59e4cc3SRick Macklem
238c59e4cc3SRick Macklem ct->ct_xid++;
239c59e4cc3SRick Macklem xid = ct->ct_xid;
240c59e4cc3SRick Macklem
241c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
242c59e4cc3SRick Macklem
243c59e4cc3SRick Macklem /*
244c59e4cc3SRick Macklem * Leave space to pre-pend the record mark.
245c59e4cc3SRick Macklem */
246c59e4cc3SRick Macklem mreq = m_gethdr(M_WAITOK, MT_DATA);
247c59e4cc3SRick Macklem mreq->m_data += sizeof(uint32_t);
248c59e4cc3SRick Macklem KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
249c59e4cc3SRick Macklem ("RPC header too big"));
250c59e4cc3SRick Macklem bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
251c59e4cc3SRick Macklem mreq->m_len = ct->ct_mpos;
252c59e4cc3SRick Macklem
253c59e4cc3SRick Macklem /*
254c59e4cc3SRick Macklem * The XID is the first thing in the request.
255c59e4cc3SRick Macklem */
256c59e4cc3SRick Macklem *mtod(mreq, uint32_t *) = htonl(xid);
257c59e4cc3SRick Macklem
258c59e4cc3SRick Macklem xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
259c59e4cc3SRick Macklem
260c59e4cc3SRick Macklem errp->re_status = stat = RPC_SUCCESS;
261c59e4cc3SRick Macklem
262c59e4cc3SRick Macklem if ((!XDR_PUTINT32(&xdrs, &proc)) ||
263c59e4cc3SRick Macklem (!AUTH_MARSHALL(auth, xid, &xdrs,
264c59e4cc3SRick Macklem m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
265c59e4cc3SRick Macklem errp->re_status = stat = RPC_CANTENCODEARGS;
266c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
267c59e4cc3SRick Macklem goto out;
268c59e4cc3SRick Macklem }
269c59e4cc3SRick Macklem mreq->m_pkthdr.len = m_length(mreq, NULL);
270c59e4cc3SRick Macklem
271c59e4cc3SRick Macklem /*
272c59e4cc3SRick Macklem * Prepend a record marker containing the packet length.
273c59e4cc3SRick Macklem */
274c59e4cc3SRick Macklem M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
275c59e4cc3SRick Macklem *mtod(mreq, uint32_t *) =
276c59e4cc3SRick Macklem htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
277c59e4cc3SRick Macklem
278c59e4cc3SRick Macklem cr->cr_xid = xid;
279c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
280c59e4cc3SRick Macklem /*
281c59e4cc3SRick Macklem * Check to see if the client end has already started to close down
282c59e4cc3SRick Macklem * the connection. The svc code will have set ct_error.re_status
283c59e4cc3SRick Macklem * to RPC_CANTRECV if this is the case.
284c59e4cc3SRick Macklem * If the client starts to close down the connection after this
285c59e4cc3SRick Macklem * point, it will be detected later when cr_error is checked,
286c59e4cc3SRick Macklem * since the request is in the ct_pending queue.
287c59e4cc3SRick Macklem */
288c59e4cc3SRick Macklem if (ct->ct_error.re_status == RPC_CANTRECV) {
289c59e4cc3SRick Macklem if (errp != &ct->ct_error) {
290c59e4cc3SRick Macklem errp->re_errno = ct->ct_error.re_errno;
291c59e4cc3SRick Macklem errp->re_status = RPC_CANTRECV;
292c59e4cc3SRick Macklem }
293c59e4cc3SRick Macklem stat = RPC_CANTRECV;
294c59e4cc3SRick Macklem goto out;
295c59e4cc3SRick Macklem }
296c59e4cc3SRick Macklem TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
297c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
298c59e4cc3SRick Macklem
299ab0c29afSRick Macklem /* For RPC-over-TLS, copy mrep to a chain of ext_pgs. */
300ab0c29afSRick Macklem if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
301ab0c29afSRick Macklem /*
302ab0c29afSRick Macklem * Copy the mbuf chain to a chain of
303ab0c29afSRick Macklem * ext_pgs mbuf(s) as required by KERN_TLS.
304ab0c29afSRick Macklem */
305ab0c29afSRick Macklem maxextsiz = TLS_MAX_MSG_SIZE_V10_2;
306ab0c29afSRick Macklem #ifdef KERN_TLS
307ab0c29afSRick Macklem if (rpctls_getinfo(&maxlen, false, false))
308ab0c29afSRick Macklem maxextsiz = min(maxextsiz, maxlen);
309ab0c29afSRick Macklem #endif
310ab0c29afSRick Macklem mreq = _rpc_copym_into_ext_pgs(mreq, maxextsiz);
311ab0c29afSRick Macklem }
312c59e4cc3SRick Macklem /*
313c59e4cc3SRick Macklem * sosend consumes mreq.
314c59e4cc3SRick Macklem */
315c59e4cc3SRick Macklem sx_xlock(&xprt->xp_lock);
316c59e4cc3SRick Macklem error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
317c59e4cc3SRick Macklem if (error != 0) printf("sosend=%d\n", error);
318c59e4cc3SRick Macklem mreq = NULL;
319c59e4cc3SRick Macklem if (error == EMSGSIZE) {
320c59e4cc3SRick Macklem printf("emsgsize\n");
321*e205fd31SGleb Smirnoff SOCK_SENDBUF_LOCK(xprt->xp_socket);
32243283184SGleb Smirnoff sbwait(xprt->xp_socket, SO_SND);
323*e205fd31SGleb Smirnoff SOCK_SENDBUF_UNLOCK(xprt->xp_socket);
324c59e4cc3SRick Macklem sx_xunlock(&xprt->xp_lock);
325c59e4cc3SRick Macklem AUTH_VALIDATE(auth, xid, NULL, NULL);
326c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
327c59e4cc3SRick Macklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
328c59e4cc3SRick Macklem goto call_again;
329c59e4cc3SRick Macklem }
330c59e4cc3SRick Macklem sx_xunlock(&xprt->xp_lock);
331c59e4cc3SRick Macklem
332c59e4cc3SRick Macklem reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
333c59e4cc3SRick Macklem reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
334c59e4cc3SRick Macklem reply_msg.acpted_rply.ar_verf.oa_length = 0;
335c59e4cc3SRick Macklem reply_msg.acpted_rply.ar_results.where = NULL;
336c59e4cc3SRick Macklem reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
337c59e4cc3SRick Macklem
338c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
339c59e4cc3SRick Macklem if (error) {
340c59e4cc3SRick Macklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
341c59e4cc3SRick Macklem errp->re_errno = error;
342c59e4cc3SRick Macklem errp->re_status = stat = RPC_CANTSEND;
343c59e4cc3SRick Macklem goto out;
344c59e4cc3SRick Macklem }
345c59e4cc3SRick Macklem
346c59e4cc3SRick Macklem /*
347c59e4cc3SRick Macklem * Check to see if we got an upcall while waiting for the
348c59e4cc3SRick Macklem * lock. In both these cases, the request has been removed
349c59e4cc3SRick Macklem * from ct->ct_pending.
350c59e4cc3SRick Macklem */
351c59e4cc3SRick Macklem if (cr->cr_error) {
352c59e4cc3SRick Macklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
353c59e4cc3SRick Macklem errp->re_errno = cr->cr_error;
354c59e4cc3SRick Macklem errp->re_status = stat = RPC_CANTRECV;
355c59e4cc3SRick Macklem goto out;
356c59e4cc3SRick Macklem }
357c59e4cc3SRick Macklem if (cr->cr_mrep) {
358c59e4cc3SRick Macklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
359c59e4cc3SRick Macklem goto got_reply;
360c59e4cc3SRick Macklem }
361c59e4cc3SRick Macklem
362c59e4cc3SRick Macklem /*
363c59e4cc3SRick Macklem * Hack to provide rpc-based message passing
364c59e4cc3SRick Macklem */
365c59e4cc3SRick Macklem if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
366c59e4cc3SRick Macklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
367c59e4cc3SRick Macklem errp->re_status = stat = RPC_TIMEDOUT;
368c59e4cc3SRick Macklem goto out;
369c59e4cc3SRick Macklem }
370c59e4cc3SRick Macklem
371c59e4cc3SRick Macklem error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
372c59e4cc3SRick Macklem tvtohz(&timeout));
373c59e4cc3SRick Macklem
374c59e4cc3SRick Macklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
375c59e4cc3SRick Macklem
376c59e4cc3SRick Macklem if (error) {
377c59e4cc3SRick Macklem /*
378c59e4cc3SRick Macklem * The sleep returned an error so our request is still
379c59e4cc3SRick Macklem * on the list. Turn the error code into an
380c59e4cc3SRick Macklem * appropriate client status.
381c59e4cc3SRick Macklem */
382c59e4cc3SRick Macklem errp->re_errno = error;
383c59e4cc3SRick Macklem switch (error) {
384c59e4cc3SRick Macklem case EINTR:
385c59e4cc3SRick Macklem stat = RPC_INTR;
386c59e4cc3SRick Macklem break;
387c59e4cc3SRick Macklem case EWOULDBLOCK:
388c59e4cc3SRick Macklem stat = RPC_TIMEDOUT;
389c59e4cc3SRick Macklem break;
390c59e4cc3SRick Macklem default:
391c59e4cc3SRick Macklem stat = RPC_CANTRECV;
39274b8d63dSPedro F. Giffuni }
393c59e4cc3SRick Macklem errp->re_status = stat;
394c59e4cc3SRick Macklem goto out;
395c59e4cc3SRick Macklem } else {
396c59e4cc3SRick Macklem /*
397c59e4cc3SRick Macklem * We were woken up by the svc thread. If the
398c59e4cc3SRick Macklem * upcall had a receive error, report that,
399c59e4cc3SRick Macklem * otherwise we have a reply.
400c59e4cc3SRick Macklem */
401c59e4cc3SRick Macklem if (cr->cr_error) {
402c59e4cc3SRick Macklem errp->re_errno = cr->cr_error;
403c59e4cc3SRick Macklem errp->re_status = stat = RPC_CANTRECV;
404c59e4cc3SRick Macklem goto out;
405c59e4cc3SRick Macklem }
406c59e4cc3SRick Macklem }
407c59e4cc3SRick Macklem
408c59e4cc3SRick Macklem got_reply:
409c59e4cc3SRick Macklem /*
410c59e4cc3SRick Macklem * Now decode and validate the response. We need to drop the
411c59e4cc3SRick Macklem * lock since xdr_replymsg may end up sleeping in malloc.
412c59e4cc3SRick Macklem */
413c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
414c59e4cc3SRick Macklem
415c59e4cc3SRick Macklem if (ext && ext->rc_feedback)
416c59e4cc3SRick Macklem ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
417c59e4cc3SRick Macklem
418c59e4cc3SRick Macklem xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
419c59e4cc3SRick Macklem ok = xdr_replymsg(&xdrs, &reply_msg);
420c59e4cc3SRick Macklem cr->cr_mrep = NULL;
421c59e4cc3SRick Macklem
422c59e4cc3SRick Macklem if (ok) {
423c59e4cc3SRick Macklem if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
424c59e4cc3SRick Macklem (reply_msg.acpted_rply.ar_stat == SUCCESS))
425c59e4cc3SRick Macklem errp->re_status = stat = RPC_SUCCESS;
426c59e4cc3SRick Macklem else
427c59e4cc3SRick Macklem stat = _seterr_reply(&reply_msg, errp);
428c59e4cc3SRick Macklem
429c59e4cc3SRick Macklem if (stat == RPC_SUCCESS) {
430c59e4cc3SRick Macklem results = xdrmbuf_getall(&xdrs);
431c59e4cc3SRick Macklem if (!AUTH_VALIDATE(auth, xid,
432c59e4cc3SRick Macklem &reply_msg.acpted_rply.ar_verf, &results)) {
433c59e4cc3SRick Macklem errp->re_status = stat = RPC_AUTHERROR;
434c59e4cc3SRick Macklem errp->re_why = AUTH_INVALIDRESP;
435c59e4cc3SRick Macklem } else {
436c59e4cc3SRick Macklem KASSERT(results,
437c59e4cc3SRick Macklem ("auth validated but no result"));
438c59e4cc3SRick Macklem *resultsp = results;
439c59e4cc3SRick Macklem }
440c59e4cc3SRick Macklem } /* end successful completion */
441c59e4cc3SRick Macklem /*
4426244c6e7SPedro F. Giffuni * If unsuccessful AND error is an authentication error
443c59e4cc3SRick Macklem * then refresh credentials and try again, else break
444c59e4cc3SRick Macklem */
445c59e4cc3SRick Macklem else if (stat == RPC_AUTHERROR)
446c59e4cc3SRick Macklem /* maybe our credentials need to be refreshed ... */
447c59e4cc3SRick Macklem if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
448c59e4cc3SRick Macklem nrefreshes--;
449c59e4cc3SRick Macklem XDR_DESTROY(&xdrs);
450c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
451c59e4cc3SRick Macklem goto call_again;
452c59e4cc3SRick Macklem }
453c59e4cc3SRick Macklem /* end of unsuccessful completion */
454c59e4cc3SRick Macklem /* end of valid reply message */
455c59e4cc3SRick Macklem } else
456c59e4cc3SRick Macklem errp->re_status = stat = RPC_CANTDECODERES;
457c59e4cc3SRick Macklem XDR_DESTROY(&xdrs);
458c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
459c59e4cc3SRick Macklem out:
460c59e4cc3SRick Macklem mtx_assert(&ct->ct_lock, MA_OWNED);
461c59e4cc3SRick Macklem
462c59e4cc3SRick Macklem KASSERT(stat != RPC_SUCCESS || *resultsp,
463c59e4cc3SRick Macklem ("RPC_SUCCESS without reply"));
464c59e4cc3SRick Macklem
465c59e4cc3SRick Macklem if (mreq != NULL)
466c59e4cc3SRick Macklem m_freem(mreq);
467c59e4cc3SRick Macklem if (cr->cr_mrep != NULL)
468c59e4cc3SRick Macklem m_freem(cr->cr_mrep);
469c59e4cc3SRick Macklem
470c59e4cc3SRick Macklem ct->ct_threads--;
471c59e4cc3SRick Macklem if (ct->ct_closing)
472c59e4cc3SRick Macklem wakeup(ct);
473c59e4cc3SRick Macklem
474c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
475c59e4cc3SRick Macklem
476c59e4cc3SRick Macklem if (auth && stat != RPC_SUCCESS)
477c59e4cc3SRick Macklem AUTH_VALIDATE(auth, xid, NULL, NULL);
478c59e4cc3SRick Macklem
479c59e4cc3SRick Macklem free(cr, M_RPC);
480c59e4cc3SRick Macklem
481c59e4cc3SRick Macklem return (stat);
482c59e4cc3SRick Macklem }
483c59e4cc3SRick Macklem
484c59e4cc3SRick Macklem static void
clnt_bck_geterr(CLIENT * cl,struct rpc_err * errp)485c59e4cc3SRick Macklem clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
486c59e4cc3SRick Macklem {
487c59e4cc3SRick Macklem struct ct_data *ct = (struct ct_data *) cl->cl_private;
488c59e4cc3SRick Macklem
489c59e4cc3SRick Macklem *errp = ct->ct_error;
490c59e4cc3SRick Macklem }
491c59e4cc3SRick Macklem
492c59e4cc3SRick Macklem static bool_t
clnt_bck_freeres(CLIENT * cl,xdrproc_t xdr_res,void * res_ptr)493c59e4cc3SRick Macklem clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
494c59e4cc3SRick Macklem {
495c59e4cc3SRick Macklem XDR xdrs;
496c59e4cc3SRick Macklem bool_t dummy;
497c59e4cc3SRick Macklem
498c59e4cc3SRick Macklem xdrs.x_op = XDR_FREE;
499c59e4cc3SRick Macklem dummy = (*xdr_res)(&xdrs, res_ptr);
500c59e4cc3SRick Macklem
501c59e4cc3SRick Macklem return (dummy);
502c59e4cc3SRick Macklem }
503c59e4cc3SRick Macklem
504c59e4cc3SRick Macklem /*ARGSUSED*/
505c59e4cc3SRick Macklem static void
clnt_bck_abort(CLIENT * cl)506c59e4cc3SRick Macklem clnt_bck_abort(CLIENT *cl)
507c59e4cc3SRick Macklem {
508c59e4cc3SRick Macklem }
509c59e4cc3SRick Macklem
510c59e4cc3SRick Macklem static bool_t
clnt_bck_control(CLIENT * cl,u_int request,void * info)511c59e4cc3SRick Macklem clnt_bck_control(CLIENT *cl, u_int request, void *info)
512c59e4cc3SRick Macklem {
513c59e4cc3SRick Macklem
514c59e4cc3SRick Macklem return (TRUE);
515c59e4cc3SRick Macklem }
516c59e4cc3SRick Macklem
517c59e4cc3SRick Macklem static void
clnt_bck_close(CLIENT * cl)518c59e4cc3SRick Macklem clnt_bck_close(CLIENT *cl)
519c59e4cc3SRick Macklem {
520c59e4cc3SRick Macklem struct ct_data *ct = (struct ct_data *) cl->cl_private;
521c59e4cc3SRick Macklem
522c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
523c59e4cc3SRick Macklem
524c59e4cc3SRick Macklem if (ct->ct_closed) {
525c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
526c59e4cc3SRick Macklem return;
527c59e4cc3SRick Macklem }
528c59e4cc3SRick Macklem
529c59e4cc3SRick Macklem if (ct->ct_closing) {
530c59e4cc3SRick Macklem while (ct->ct_closing)
531c59e4cc3SRick Macklem msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
532c59e4cc3SRick Macklem KASSERT(ct->ct_closed, ("client should be closed"));
533c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
534c59e4cc3SRick Macklem return;
535c59e4cc3SRick Macklem }
536c59e4cc3SRick Macklem
537c59e4cc3SRick Macklem ct->ct_closing = FALSE;
538c59e4cc3SRick Macklem ct->ct_closed = TRUE;
539c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
540c59e4cc3SRick Macklem wakeup(ct);
541c59e4cc3SRick Macklem }
542c59e4cc3SRick Macklem
543c59e4cc3SRick Macklem static void
clnt_bck_destroy(CLIENT * cl)544c59e4cc3SRick Macklem clnt_bck_destroy(CLIENT *cl)
545c59e4cc3SRick Macklem {
546c59e4cc3SRick Macklem struct ct_data *ct = (struct ct_data *) cl->cl_private;
547c59e4cc3SRick Macklem
548c59e4cc3SRick Macklem clnt_bck_close(cl);
549c59e4cc3SRick Macklem
550c59e4cc3SRick Macklem mtx_destroy(&ct->ct_lock);
551c59e4cc3SRick Macklem mem_free(ct, sizeof(struct ct_data));
552c59e4cc3SRick Macklem if (cl->cl_netid && cl->cl_netid[0])
553c59e4cc3SRick Macklem mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
554c59e4cc3SRick Macklem if (cl->cl_tp && cl->cl_tp[0])
555c59e4cc3SRick Macklem mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
556c59e4cc3SRick Macklem mem_free(cl, sizeof(CLIENT));
557c59e4cc3SRick Macklem }
558c59e4cc3SRick Macklem
559c59e4cc3SRick Macklem /*
560c59e4cc3SRick Macklem * This call is done by the svc code when a backchannel RPC reply is
561c59e4cc3SRick Macklem * received.
562e1a907a2SRick Macklem * For the server end, where callback RPCs to the client are performed,
563e1a907a2SRick Macklem * xp_p2 points to the "CLIENT" and not the associated "struct ct_data"
564e1a907a2SRick Macklem * so that svc_vc_destroy() can CLNT_RELEASE() the reference count on it.
565c59e4cc3SRick Macklem */
566c59e4cc3SRick Macklem void
clnt_bck_svccall(void * arg,struct mbuf * mrep,uint32_t xid)567c59e4cc3SRick Macklem clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
568c59e4cc3SRick Macklem {
569e1a907a2SRick Macklem CLIENT *cl = (CLIENT *)arg;
570e1a907a2SRick Macklem struct ct_data *ct;
571c59e4cc3SRick Macklem struct ct_request *cr;
572c59e4cc3SRick Macklem int foundreq;
573c59e4cc3SRick Macklem
574e1a907a2SRick Macklem ct = (struct ct_data *)cl->cl_private;
575c59e4cc3SRick Macklem mtx_lock(&ct->ct_lock);
576e1a907a2SRick Macklem if (ct->ct_closing || ct->ct_closed) {
577e1a907a2SRick Macklem mtx_unlock(&ct->ct_lock);
578e1a907a2SRick Macklem m_freem(mrep);
579e1a907a2SRick Macklem return;
580e1a907a2SRick Macklem }
581e1a907a2SRick Macklem
582c59e4cc3SRick Macklem ct->ct_upcallrefs++;
583c59e4cc3SRick Macklem /*
584c59e4cc3SRick Macklem * See if we can match this reply to a request.
585c59e4cc3SRick Macklem */
586c59e4cc3SRick Macklem foundreq = 0;
587c59e4cc3SRick Macklem TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
588c59e4cc3SRick Macklem if (cr->cr_xid == xid) {
589c59e4cc3SRick Macklem /*
590c59e4cc3SRick Macklem * This one matches. We leave the reply mbuf list in
591c59e4cc3SRick Macklem * cr->cr_mrep. Set the XID to zero so that we will
592c59e4cc3SRick Macklem * ignore any duplicated replies.
593c59e4cc3SRick Macklem */
594c59e4cc3SRick Macklem cr->cr_xid = 0;
595c59e4cc3SRick Macklem cr->cr_mrep = mrep;
596c59e4cc3SRick Macklem cr->cr_error = 0;
597c59e4cc3SRick Macklem foundreq = 1;
598c59e4cc3SRick Macklem wakeup(cr);
599c59e4cc3SRick Macklem break;
600c59e4cc3SRick Macklem }
601c59e4cc3SRick Macklem }
602c59e4cc3SRick Macklem
603c59e4cc3SRick Macklem ct->ct_upcallrefs--;
604c59e4cc3SRick Macklem if (ct->ct_upcallrefs < 0)
605c59e4cc3SRick Macklem panic("rpcvc svccall refcnt");
606c59e4cc3SRick Macklem if (ct->ct_upcallrefs == 0)
607c59e4cc3SRick Macklem wakeup(&ct->ct_upcallrefs);
608c59e4cc3SRick Macklem mtx_unlock(&ct->ct_lock);
609c59e4cc3SRick Macklem if (foundreq == 0)
610c59e4cc3SRick Macklem m_freem(mrep);
611c59e4cc3SRick Macklem }
612c59e4cc3SRick Macklem
613