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