1dfdcada3SDoug Rabson /* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ 2dfdcada3SDoug Rabson 32e322d37SHiroki Sato /*- 451369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 551369649SPedro F. Giffuni * 62e322d37SHiroki Sato * Copyright (c) 2009, Sun Microsystems, Inc. 72e322d37SHiroki Sato * All rights reserved. 8dfdcada3SDoug Rabson * 92e322d37SHiroki Sato * Redistribution and use in source and binary forms, with or without 102e322d37SHiroki Sato * modification, are permitted provided that the following conditions are met: 112e322d37SHiroki Sato * - Redistributions of source code must retain the above copyright notice, 122e322d37SHiroki Sato * this list of conditions and the following disclaimer. 132e322d37SHiroki Sato * - Redistributions in binary form must reproduce the above copyright notice, 142e322d37SHiroki Sato * this list of conditions and the following disclaimer in the documentation 152e322d37SHiroki Sato * and/or other materials provided with the distribution. 162e322d37SHiroki Sato * - Neither the name of Sun Microsystems, Inc. nor the names of its 172e322d37SHiroki Sato * contributors may be used to endorse or promote products derived 182e322d37SHiroki Sato * from this software without specific prior written permission. 19dfdcada3SDoug Rabson * 202e322d37SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 212e322d37SHiroki Sato * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 222e322d37SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 232e322d37SHiroki Sato * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 242e322d37SHiroki Sato * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 252e322d37SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 262e322d37SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 272e322d37SHiroki Sato * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 282e322d37SHiroki Sato * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 292e322d37SHiroki Sato * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 302e322d37SHiroki Sato * POSSIBILITY OF SUCH DAMAGE. 31dfdcada3SDoug Rabson */ 32dfdcada3SDoug Rabson 33dfdcada3SDoug Rabson #include <sys/cdefs.h> 34dfdcada3SDoug Rabson /* 35dfdcada3SDoug Rabson * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 36dfdcada3SDoug Rabson * 37dfdcada3SDoug Rabson * Copyright (C) 1984, Sun Microsystems, Inc. 38dfdcada3SDoug Rabson * 39dfdcada3SDoug Rabson * TCP based RPC supports 'batched calls'. 40dfdcada3SDoug Rabson * A sequence of calls may be batched-up in a send buffer. The rpc call 41dfdcada3SDoug Rabson * return immediately to the client even though the call was not necessarily 42dfdcada3SDoug Rabson * sent. The batching occurs if the results' xdr routine is NULL (0) AND 43dfdcada3SDoug Rabson * the rpc timeout value is zero (see clnt.h, rpc). 44dfdcada3SDoug Rabson * 45dfdcada3SDoug Rabson * Clients should NOT casually batch calls that in fact return results; that is, 46dfdcada3SDoug Rabson * the server side should be aware that a call is batched and not produce any 47dfdcada3SDoug Rabson * return message. Batched calls that produce many result messages can 48dfdcada3SDoug Rabson * deadlock (netlock) the client and the server.... 49dfdcada3SDoug Rabson * 50dfdcada3SDoug Rabson * Now go hang yourself. 51dfdcada3SDoug Rabson */ 52dfdcada3SDoug Rabson 53ab0c29afSRick Macklem #include "opt_kern_tls.h" 54ab0c29afSRick Macklem 55dfdcada3SDoug Rabson #include <sys/param.h> 56dfdcada3SDoug Rabson #include <sys/systm.h> 57dfd174d6SRick Macklem #include <sys/kernel.h> 58ab0c29afSRick Macklem #include <sys/kthread.h> 59ab0c29afSRick Macklem #include <sys/ktls.h> 60dfdcada3SDoug Rabson #include <sys/lock.h> 61dfdcada3SDoug Rabson #include <sys/malloc.h> 62dfdcada3SDoug Rabson #include <sys/mbuf.h> 63dfdcada3SDoug Rabson #include <sys/mutex.h> 64dfdcada3SDoug Rabson #include <sys/pcpu.h> 65dfdcada3SDoug Rabson #include <sys/proc.h> 66a9148abdSDoug Rabson #include <sys/protosw.h> 67dfdcada3SDoug Rabson #include <sys/socket.h> 68dfdcada3SDoug Rabson #include <sys/socketvar.h> 69e2adc47dSRick Macklem #include <sys/sx.h> 70dfdcada3SDoug Rabson #include <sys/syslog.h> 71dfdcada3SDoug Rabson #include <sys/time.h> 72dfdcada3SDoug Rabson #include <sys/uio.h> 730348c661SMarko Zec 740348c661SMarko Zec #include <net/vnet.h> 750348c661SMarko Zec 76a9148abdSDoug Rabson #include <netinet/tcp.h> 77dfdcada3SDoug Rabson 78dfdcada3SDoug Rabson #include <rpc/rpc.h> 79ee31b83aSDoug Rabson #include <rpc/rpc_com.h> 80e2adc47dSRick Macklem #include <rpc/krpc.h> 81ab0c29afSRick Macklem #include <rpc/rpcsec_tls.h> 82dfdcada3SDoug Rabson 83dfdcada3SDoug Rabson struct cmessage { 84dfdcada3SDoug Rabson struct cmsghdr cmsg; 85dfdcada3SDoug Rabson struct cmsgcred cmcred; 86dfdcada3SDoug Rabson }; 87dfdcada3SDoug Rabson 88c675522fSDoug Rabson static enum clnt_stat clnt_vc_call(CLIENT *, struct rpc_callextra *, 89a9148abdSDoug Rabson rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); 90dfdcada3SDoug Rabson static void clnt_vc_geterr(CLIENT *, struct rpc_err *); 91dfdcada3SDoug Rabson static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *); 92dfdcada3SDoug Rabson static void clnt_vc_abort(CLIENT *); 93dfdcada3SDoug Rabson static bool_t clnt_vc_control(CLIENT *, u_int, void *); 94a9148abdSDoug Rabson static void clnt_vc_close(CLIENT *); 95dfdcada3SDoug Rabson static void clnt_vc_destroy(CLIENT *); 96dfdcada3SDoug Rabson static bool_t time_not_ok(struct timeval *); 9774fb0ba7SJohn Baldwin static int clnt_vc_soupcall(struct socket *so, void *arg, int waitflag); 98ab0c29afSRick Macklem static void clnt_vc_dotlsupcall(void *data); 99dfdcada3SDoug Rabson 10020d728b5SMark Johnston static const struct clnt_ops clnt_vc_ops = { 101dfdcada3SDoug Rabson .cl_call = clnt_vc_call, 102dfdcada3SDoug Rabson .cl_abort = clnt_vc_abort, 103dfdcada3SDoug Rabson .cl_geterr = clnt_vc_geterr, 104dfdcada3SDoug Rabson .cl_freeres = clnt_vc_freeres, 105a9148abdSDoug Rabson .cl_close = clnt_vc_close, 106dfdcada3SDoug Rabson .cl_destroy = clnt_vc_destroy, 107dfdcada3SDoug Rabson .cl_control = clnt_vc_control 108dfdcada3SDoug Rabson }; 109dfdcada3SDoug Rabson 1103144f812SRick Macklem static void clnt_vc_upcallsdone(struct ct_data *); 1113144f812SRick Macklem 112dfdcada3SDoug Rabson /* 113dfdcada3SDoug Rabson * Create a client handle for a connection. 114dfdcada3SDoug Rabson * Default options are set, which the user can change using clnt_control()'s. 115dfdcada3SDoug Rabson * The rpc/vc package does buffering similar to stdio, so the client 116dfdcada3SDoug Rabson * must pick send and receive buffer sizes, 0 => use the default. 117dfdcada3SDoug Rabson * NB: fd is copied into a private area. 118dfdcada3SDoug Rabson * NB: The rpch->cl_auth is set null authentication. Caller may wish to 119dfdcada3SDoug Rabson * set this something more useful. 120dfdcada3SDoug Rabson * 121dfdcada3SDoug Rabson * fd should be an open socket 122dfdcada3SDoug Rabson */ 123dfdcada3SDoug Rabson CLIENT * 124dfdcada3SDoug Rabson clnt_vc_create( 125dfdcada3SDoug Rabson struct socket *so, /* open file descriptor */ 126dfdcada3SDoug Rabson struct sockaddr *raddr, /* servers address */ 127dfdcada3SDoug Rabson const rpcprog_t prog, /* program number */ 128dfdcada3SDoug Rabson const rpcvers_t vers, /* version number */ 129dfdcada3SDoug Rabson size_t sendsz, /* buffer recv size */ 1307b67bd9fSRick Macklem size_t recvsz, /* buffer send size */ 1317b67bd9fSRick Macklem int intrflag) /* interruptible */ 132dfdcada3SDoug Rabson { 133dfdcada3SDoug Rabson CLIENT *cl; /* client handle */ 134dfdcada3SDoug Rabson struct ct_data *ct = NULL; /* client handle */ 135dfdcada3SDoug Rabson struct timeval now; 136dfdcada3SDoug Rabson struct rpc_msg call_msg; 137dfdcada3SDoug Rabson static uint32_t disrupt; 138dfdcada3SDoug Rabson struct __rpc_sockinfo si; 139dfdcada3SDoug Rabson XDR xdrs; 1407b67bd9fSRick Macklem int error, interrupted, one = 1, sleep_flag; 141a9148abdSDoug Rabson struct sockopt sopt; 142dfdcada3SDoug Rabson 143dfdcada3SDoug Rabson if (disrupt == 0) 144dfdcada3SDoug Rabson disrupt = (uint32_t)(long)raddr; 145dfdcada3SDoug Rabson 146dfdcada3SDoug Rabson cl = (CLIENT *)mem_alloc(sizeof (*cl)); 147dfdcada3SDoug Rabson ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 148dfdcada3SDoug Rabson 149dfdcada3SDoug Rabson mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF); 150c675522fSDoug Rabson ct->ct_threads = 0; 151c675522fSDoug Rabson ct->ct_closing = FALSE; 152a9148abdSDoug Rabson ct->ct_closed = FALSE; 1533144f812SRick Macklem ct->ct_upcallrefs = 0; 154ab0c29afSRick Macklem ct->ct_rcvstate = RPCRCVSTATE_NORMAL; 155dfdcada3SDoug Rabson 156f79a8585SGleb Smirnoff if ((so->so_state & SS_ISCONNECTED) == 0) { 157dfdcada3SDoug Rabson error = soconnect(so, raddr, curthread); 158c675522fSDoug Rabson SOCK_LOCK(so); 159c675522fSDoug Rabson interrupted = 0; 1607b67bd9fSRick Macklem sleep_flag = PSOCK; 1617b67bd9fSRick Macklem if (intrflag != 0) 1623b14c753SJohn Baldwin sleep_flag |= PCATCH; 163c675522fSDoug Rabson while ((so->so_state & SS_ISCONNECTING) 164c675522fSDoug Rabson && so->so_error == 0) { 165c675522fSDoug Rabson error = msleep(&so->so_timeo, SOCK_MTX(so), 1667b67bd9fSRick Macklem sleep_flag, "connec", 0); 167dfdcada3SDoug Rabson if (error) { 168c675522fSDoug Rabson if (error == EINTR || error == ERESTART) 169c675522fSDoug Rabson interrupted = 1; 170c675522fSDoug Rabson break; 171c675522fSDoug Rabson } 172c675522fSDoug Rabson } 173c675522fSDoug Rabson if (error == 0) { 174c675522fSDoug Rabson error = so->so_error; 175c675522fSDoug Rabson so->so_error = 0; 176c675522fSDoug Rabson } 177c675522fSDoug Rabson SOCK_UNLOCK(so); 178c675522fSDoug Rabson if (error) { 179c675522fSDoug Rabson if (!interrupted) 180c675522fSDoug Rabson so->so_state &= ~SS_ISCONNECTING; 181dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_SYSTEMERROR; 182dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = error; 183dfdcada3SDoug Rabson goto err; 184dfdcada3SDoug Rabson } 185dfdcada3SDoug Rabson } 186dfdcada3SDoug Rabson 1870348c661SMarko Zec if (!__rpc_socket2sockinfo(so, &si)) { 188dfdcada3SDoug Rabson goto err; 1890348c661SMarko Zec } 190dfdcada3SDoug Rabson 191a9148abdSDoug Rabson if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 192a9148abdSDoug Rabson bzero(&sopt, sizeof(sopt)); 193a9148abdSDoug Rabson sopt.sopt_dir = SOPT_SET; 194a9148abdSDoug Rabson sopt.sopt_level = SOL_SOCKET; 195a9148abdSDoug Rabson sopt.sopt_name = SO_KEEPALIVE; 196a9148abdSDoug Rabson sopt.sopt_val = &one; 197a9148abdSDoug Rabson sopt.sopt_valsize = sizeof(one); 198a9148abdSDoug Rabson sosetopt(so, &sopt); 199a9148abdSDoug Rabson } 200a9148abdSDoug Rabson 201a9148abdSDoug Rabson if (so->so_proto->pr_protocol == IPPROTO_TCP) { 202a9148abdSDoug Rabson bzero(&sopt, sizeof(sopt)); 203a9148abdSDoug Rabson sopt.sopt_dir = SOPT_SET; 204a9148abdSDoug Rabson sopt.sopt_level = IPPROTO_TCP; 205a9148abdSDoug Rabson sopt.sopt_name = TCP_NODELAY; 206a9148abdSDoug Rabson sopt.sopt_val = &one; 207a9148abdSDoug Rabson sopt.sopt_valsize = sizeof(one); 208a9148abdSDoug Rabson sosetopt(so, &sopt); 209a9148abdSDoug Rabson } 210a9148abdSDoug Rabson 211dfdcada3SDoug Rabson ct->ct_closeit = FALSE; 212dfdcada3SDoug Rabson 213dfdcada3SDoug Rabson /* 214dfdcada3SDoug Rabson * Set up private data struct 215dfdcada3SDoug Rabson */ 216dfdcada3SDoug Rabson ct->ct_socket = so; 217dfdcada3SDoug Rabson ct->ct_wait.tv_sec = -1; 218dfdcada3SDoug Rabson ct->ct_wait.tv_usec = -1; 219dfdcada3SDoug Rabson memcpy(&ct->ct_addr, raddr, raddr->sa_len); 220dfdcada3SDoug Rabson 221dfdcada3SDoug Rabson /* 222dfdcada3SDoug Rabson * Initialize call message 223dfdcada3SDoug Rabson */ 224dfdcada3SDoug Rabson getmicrotime(&now); 225dfdcada3SDoug Rabson ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now); 226dfdcada3SDoug Rabson call_msg.rm_xid = ct->ct_xid; 227dfdcada3SDoug Rabson call_msg.rm_direction = CALL; 228dfdcada3SDoug Rabson call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 229dfdcada3SDoug Rabson call_msg.rm_call.cb_prog = (uint32_t)prog; 230dfdcada3SDoug Rabson call_msg.rm_call.cb_vers = (uint32_t)vers; 231dfdcada3SDoug Rabson 232dfdcada3SDoug Rabson /* 233dfdcada3SDoug Rabson * pre-serialize the static part of the call msg and stash it away 234dfdcada3SDoug Rabson */ 235dfdcada3SDoug Rabson xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE, 236dfdcada3SDoug Rabson XDR_ENCODE); 2379d04973bSGleb Smirnoff if (! xdr_callhdr(&xdrs, &call_msg)) 238dfdcada3SDoug Rabson goto err; 239dfdcada3SDoug Rabson ct->ct_mpos = XDR_GETPOS(&xdrs); 240dfdcada3SDoug Rabson XDR_DESTROY(&xdrs); 241dfdcada3SDoug Rabson ct->ct_waitchan = "rpcrecv"; 242dfdcada3SDoug Rabson ct->ct_waitflag = 0; 243dfdcada3SDoug Rabson 244dfdcada3SDoug Rabson /* 245dfdcada3SDoug Rabson * Create a client handle which uses xdrrec for serialization 246dfdcada3SDoug Rabson * and authnone for authentication. 247dfdcada3SDoug Rabson */ 248cec077bcSRick Macklem sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 249cec077bcSRick Macklem recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 250cec077bcSRick Macklem error = soreserve(ct->ct_socket, sendsz, recvsz); 2519d04973bSGleb Smirnoff if (error != 0) 252cec077bcSRick Macklem goto err; 253c675522fSDoug Rabson cl->cl_refs = 1; 254dfdcada3SDoug Rabson cl->cl_ops = &clnt_vc_ops; 255dfdcada3SDoug Rabson cl->cl_private = ct; 256dfdcada3SDoug Rabson cl->cl_auth = authnone_create(); 257dfdcada3SDoug Rabson 258e205fd31SGleb Smirnoff SOCK_RECVBUF_LOCK(ct->ct_socket); 25974fb0ba7SJohn Baldwin soupcall_set(ct->ct_socket, SO_RCV, clnt_vc_soupcall, ct); 260e205fd31SGleb Smirnoff SOCK_RECVBUF_UNLOCK(ct->ct_socket); 261dfdcada3SDoug Rabson 2624302e8b6SRick Macklem ct->ct_raw = NULL; 263dfdcada3SDoug Rabson ct->ct_record = NULL; 264dfdcada3SDoug Rabson ct->ct_record_resid = 0; 265ab0c29afSRick Macklem ct->ct_sslrefno = 0; 266dfdcada3SDoug Rabson TAILQ_INIT(&ct->ct_pending); 267dfdcada3SDoug Rabson return (cl); 268dfdcada3SDoug Rabson 269dfdcada3SDoug Rabson err: 270a9ccfd56SDoug Rabson mtx_destroy(&ct->ct_lock); 271dfdcada3SDoug Rabson mem_free(ct, sizeof (struct ct_data)); 272dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 2737d3db235SEnji Cooper 274dfdcada3SDoug Rabson return ((CLIENT *)NULL); 275dfdcada3SDoug Rabson } 276dfdcada3SDoug Rabson 277dfdcada3SDoug Rabson static enum clnt_stat 278dfdcada3SDoug Rabson clnt_vc_call( 279a9148abdSDoug Rabson CLIENT *cl, /* client handle */ 280a9148abdSDoug Rabson struct rpc_callextra *ext, /* call metadata */ 281a9148abdSDoug Rabson rpcproc_t proc, /* procedure number */ 282a9148abdSDoug Rabson struct mbuf *args, /* pointer to args */ 283a9148abdSDoug Rabson struct mbuf **resultsp, /* pointer to results */ 284dfdcada3SDoug Rabson struct timeval utimeout) 285dfdcada3SDoug Rabson { 286dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 287c675522fSDoug Rabson AUTH *auth; 288a9148abdSDoug Rabson struct rpc_err *errp; 289a9148abdSDoug Rabson enum clnt_stat stat; 290dfdcada3SDoug Rabson XDR xdrs; 291dfdcada3SDoug Rabson struct rpc_msg reply_msg; 292dfdcada3SDoug Rabson bool_t ok; 293dfdcada3SDoug Rabson int nrefreshes = 2; /* number of times to refresh cred */ 294dfdcada3SDoug Rabson struct timeval timeout; 295dfdcada3SDoug Rabson uint32_t xid; 296a9148abdSDoug Rabson struct mbuf *mreq = NULL, *results; 297c675522fSDoug Rabson struct ct_request *cr; 298ab0c29afSRick Macklem int error, maxextsiz, trycnt; 299ab0c29afSRick Macklem #ifdef KERN_TLS 300ab0c29afSRick Macklem u_int maxlen; 301ab0c29afSRick Macklem #endif 302dfdcada3SDoug Rabson 303c675522fSDoug Rabson cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK); 304c675522fSDoug Rabson 305dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 306dfdcada3SDoug Rabson 307a9148abdSDoug Rabson if (ct->ct_closing || ct->ct_closed) { 308c675522fSDoug Rabson mtx_unlock(&ct->ct_lock); 309c675522fSDoug Rabson free(cr, M_RPC); 310c675522fSDoug Rabson return (RPC_CANTSEND); 311c675522fSDoug Rabson } 312c675522fSDoug Rabson ct->ct_threads++; 313c675522fSDoug Rabson 314a9148abdSDoug Rabson if (ext) { 315c675522fSDoug Rabson auth = ext->rc_auth; 316a9148abdSDoug Rabson errp = &ext->rc_err; 317a9148abdSDoug Rabson } else { 318c675522fSDoug Rabson auth = cl->cl_auth; 319a9148abdSDoug Rabson errp = &ct->ct_error; 320a9148abdSDoug Rabson } 321c675522fSDoug Rabson 322c675522fSDoug Rabson cr->cr_mrep = NULL; 323c675522fSDoug Rabson cr->cr_error = 0; 324dfdcada3SDoug Rabson 325dfdcada3SDoug Rabson if (ct->ct_wait.tv_usec == -1) { 326dfdcada3SDoug Rabson timeout = utimeout; /* use supplied timeout */ 327dfdcada3SDoug Rabson } else { 328dfdcada3SDoug Rabson timeout = ct->ct_wait; /* use default timeout */ 329dfdcada3SDoug Rabson } 330dfdcada3SDoug Rabson 331dfd174d6SRick Macklem /* 332dfd174d6SRick Macklem * After 15sec of looping, allow it to return RPC_CANTSEND, which will 333dfd174d6SRick Macklem * cause the clnt_reconnect layer to create a new TCP connection. 334dfd174d6SRick Macklem */ 335dfd174d6SRick Macklem trycnt = 15 * hz; 336dfdcada3SDoug Rabson call_again: 337dfdcada3SDoug Rabson mtx_assert(&ct->ct_lock, MA_OWNED); 338dfd174d6SRick Macklem if (ct->ct_closing || ct->ct_closed) { 339dfd174d6SRick Macklem ct->ct_threads--; 340dfd174d6SRick Macklem wakeup(ct); 341dfd174d6SRick Macklem mtx_unlock(&ct->ct_lock); 342dfd174d6SRick Macklem free(cr, M_RPC); 343dfd174d6SRick Macklem return (RPC_CANTSEND); 344dfd174d6SRick Macklem } 345dfdcada3SDoug Rabson 346dfdcada3SDoug Rabson ct->ct_xid++; 347dfdcada3SDoug Rabson xid = ct->ct_xid; 348dfdcada3SDoug Rabson 349dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 350dfdcada3SDoug Rabson 351dfdcada3SDoug Rabson /* 352dfdcada3SDoug Rabson * Leave space to pre-pend the record mark. 353dfdcada3SDoug Rabson */ 354bd54830bSGleb Smirnoff mreq = m_gethdr(M_WAITOK, MT_DATA); 355dfdcada3SDoug Rabson mreq->m_data += sizeof(uint32_t); 356a9148abdSDoug Rabson KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN, 357a9148abdSDoug Rabson ("RPC header too big")); 358a9148abdSDoug Rabson bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos); 359a9148abdSDoug Rabson mreq->m_len = ct->ct_mpos; 360dfdcada3SDoug Rabson 361dfdcada3SDoug Rabson /* 362dfdcada3SDoug Rabson * The XID is the first thing in the request. 363dfdcada3SDoug Rabson */ 364dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = htonl(xid); 365dfdcada3SDoug Rabson 366dfdcada3SDoug Rabson xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 367dfdcada3SDoug Rabson 368a9148abdSDoug Rabson errp->re_status = stat = RPC_SUCCESS; 369dfdcada3SDoug Rabson 370dfdcada3SDoug Rabson if ((! XDR_PUTINT32(&xdrs, &proc)) || 371a9148abdSDoug Rabson (! AUTH_MARSHALL(auth, xid, &xdrs, 372a9148abdSDoug Rabson m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 373a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTENCODEARGS; 374c675522fSDoug Rabson mtx_lock(&ct->ct_lock); 375c675522fSDoug Rabson goto out; 376dfdcada3SDoug Rabson } 377a9148abdSDoug Rabson mreq->m_pkthdr.len = m_length(mreq, NULL); 378dfdcada3SDoug Rabson 379dfdcada3SDoug Rabson /* 380dfdcada3SDoug Rabson * Prepend a record marker containing the packet length. 381dfdcada3SDoug Rabson */ 382eb1b1807SGleb Smirnoff M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK); 383dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = 384dfdcada3SDoug Rabson htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t))); 385dfdcada3SDoug Rabson 386c675522fSDoug Rabson cr->cr_xid = xid; 387dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 388f9917533SRick Macklem /* 389f9917533SRick Macklem * Check to see if the other end has already started to close down 390f9917533SRick Macklem * the connection. The upcall will have set ct_error.re_status 391f9917533SRick Macklem * to RPC_CANTRECV if this is the case. 392f9917533SRick Macklem * If the other end starts to close down the connection after this 393f9917533SRick Macklem * point, it will be detected later when cr_error is checked, 394f9917533SRick Macklem * since the request is in the ct_pending queue. 395f9917533SRick Macklem */ 396f9917533SRick Macklem if (ct->ct_error.re_status == RPC_CANTRECV) { 397f9917533SRick Macklem if (errp != &ct->ct_error) { 398f9917533SRick Macklem errp->re_errno = ct->ct_error.re_errno; 399f9917533SRick Macklem errp->re_status = RPC_CANTRECV; 400f9917533SRick Macklem } 401f9917533SRick Macklem stat = RPC_CANTRECV; 402f9917533SRick Macklem goto out; 403f9917533SRick Macklem } 404ab0c29afSRick Macklem 405ab0c29afSRick Macklem /* For TLS, wait for an upcall to be done, as required. */ 406ab0c29afSRick Macklem while ((ct->ct_rcvstate & (RPCRCVSTATE_NORMAL | 407ab0c29afSRick Macklem RPCRCVSTATE_NONAPPDATA)) == 0) 408ab0c29afSRick Macklem msleep(&ct->ct_rcvstate, &ct->ct_lock, 0, "rpcrcvst", hz); 409ab0c29afSRick Macklem 410c675522fSDoug Rabson TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link); 411dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 412dfdcada3SDoug Rabson 413ab0c29afSRick Macklem if (ct->ct_sslrefno != 0) { 414ab0c29afSRick Macklem /* 415ab0c29afSRick Macklem * Copy the mbuf chain to a chain of ext_pgs mbuf(s) 416ab0c29afSRick Macklem * as required by KERN_TLS. 417ab0c29afSRick Macklem */ 418ab0c29afSRick Macklem maxextsiz = TLS_MAX_MSG_SIZE_V10_2; 419ab0c29afSRick Macklem #ifdef KERN_TLS 420ab0c29afSRick Macklem if (rpctls_getinfo(&maxlen, false, false)) 421ab0c29afSRick Macklem maxextsiz = min(maxextsiz, maxlen); 422ab0c29afSRick Macklem #endif 423ab0c29afSRick Macklem mreq = _rpc_copym_into_ext_pgs(mreq, maxextsiz); 424ab0c29afSRick Macklem } 425dfdcada3SDoug Rabson /* 426dfdcada3SDoug Rabson * sosend consumes mreq. 427dfdcada3SDoug Rabson */ 428dfdcada3SDoug Rabson error = sosend(ct->ct_socket, NULL, NULL, mreq, NULL, 0, curthread); 429dfdcada3SDoug Rabson mreq = NULL; 430dfd174d6SRick Macklem if (error == EMSGSIZE || (error == ERESTART && 431dfd174d6SRick Macklem (ct->ct_waitflag & PCATCH) == 0 && trycnt-- > 0)) { 432e205fd31SGleb Smirnoff SOCK_SENDBUF_LOCK(ct->ct_socket); 43343283184SGleb Smirnoff sbwait(ct->ct_socket, SO_SND); 434e205fd31SGleb Smirnoff SOCK_SENDBUF_UNLOCK(ct->ct_socket); 435a9148abdSDoug Rabson AUTH_VALIDATE(auth, xid, NULL, NULL); 436a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 437a9148abdSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 438dfd174d6SRick Macklem /* Sleep for 1 clock tick before trying the sosend() again. */ 43982512c17SRick Macklem mtx_unlock(&ct->ct_lock); 44082512c17SRick Macklem pause("rpclpsnd", 1); 44182512c17SRick Macklem mtx_lock(&ct->ct_lock); 442a9148abdSDoug Rabson goto call_again; 443a9148abdSDoug Rabson } 444dfdcada3SDoug Rabson 445a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 446a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 447a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_length = 0; 448a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.where = NULL; 449a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 450dfdcada3SDoug Rabson 451dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 452dfdcada3SDoug Rabson if (error) { 453c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 454a9148abdSDoug Rabson errp->re_errno = error; 455a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 456dfdcada3SDoug Rabson goto out; 457dfdcada3SDoug Rabson } 458dfdcada3SDoug Rabson 459dfdcada3SDoug Rabson /* 460dfdcada3SDoug Rabson * Check to see if we got an upcall while waiting for the 461dfdcada3SDoug Rabson * lock. In both these cases, the request has been removed 462dfdcada3SDoug Rabson * from ct->ct_pending. 463dfdcada3SDoug Rabson */ 464c675522fSDoug Rabson if (cr->cr_error) { 465c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 466a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 467a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 468dfdcada3SDoug Rabson goto out; 469dfdcada3SDoug Rabson } 470c675522fSDoug Rabson if (cr->cr_mrep) { 471c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 472dfdcada3SDoug Rabson goto got_reply; 473dfdcada3SDoug Rabson } 474dfdcada3SDoug Rabson 475dfdcada3SDoug Rabson /* 476dfdcada3SDoug Rabson * Hack to provide rpc-based message passing 477dfdcada3SDoug Rabson */ 478dfdcada3SDoug Rabson if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 479c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 480a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 481dfdcada3SDoug Rabson goto out; 482dfdcada3SDoug Rabson } 483dfdcada3SDoug Rabson 484c675522fSDoug Rabson error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan, 485dfdcada3SDoug Rabson tvtohz(&timeout)); 486dfdcada3SDoug Rabson 487c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 488c675522fSDoug Rabson 489dfdcada3SDoug Rabson if (error) { 490dfdcada3SDoug Rabson /* 491dfdcada3SDoug Rabson * The sleep returned an error so our request is still 492dfdcada3SDoug Rabson * on the list. Turn the error code into an 493dfdcada3SDoug Rabson * appropriate client status. 494dfdcada3SDoug Rabson */ 495a9148abdSDoug Rabson errp->re_errno = error; 496dfdcada3SDoug Rabson switch (error) { 497dfdcada3SDoug Rabson case EINTR: 498a9148abdSDoug Rabson stat = RPC_INTR; 499dfdcada3SDoug Rabson break; 500dfdcada3SDoug Rabson case EWOULDBLOCK: 501a9148abdSDoug Rabson stat = RPC_TIMEDOUT; 502dfdcada3SDoug Rabson break; 503dfdcada3SDoug Rabson default: 504a9148abdSDoug Rabson stat = RPC_CANTRECV; 505dfdcada3SDoug Rabson } 506a9148abdSDoug Rabson errp->re_status = stat; 507dfdcada3SDoug Rabson goto out; 508dfdcada3SDoug Rabson } else { 509dfdcada3SDoug Rabson /* 510dfdcada3SDoug Rabson * We were woken up by the upcall. If the 511dfdcada3SDoug Rabson * upcall had a receive error, report that, 512dfdcada3SDoug Rabson * otherwise we have a reply. 513dfdcada3SDoug Rabson */ 514c675522fSDoug Rabson if (cr->cr_error) { 515a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 516a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 517dfdcada3SDoug Rabson goto out; 518dfdcada3SDoug Rabson } 519dfdcada3SDoug Rabson } 520dfdcada3SDoug Rabson 521dfdcada3SDoug Rabson got_reply: 522dfdcada3SDoug Rabson /* 523dfdcada3SDoug Rabson * Now decode and validate the response. We need to drop the 524dfdcada3SDoug Rabson * lock since xdr_replymsg may end up sleeping in malloc. 525dfdcada3SDoug Rabson */ 526dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 527dfdcada3SDoug Rabson 528a9148abdSDoug Rabson if (ext && ext->rc_feedback) 529a9148abdSDoug Rabson ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg); 530a9148abdSDoug Rabson 531c675522fSDoug Rabson xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); 532dfdcada3SDoug Rabson ok = xdr_replymsg(&xdrs, &reply_msg); 533c675522fSDoug Rabson cr->cr_mrep = NULL; 534dfdcada3SDoug Rabson 535dfdcada3SDoug Rabson if (ok) { 536dfdcada3SDoug Rabson if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 537dfdcada3SDoug Rabson (reply_msg.acpted_rply.ar_stat == SUCCESS)) 538a9148abdSDoug Rabson errp->re_status = stat = RPC_SUCCESS; 539dfdcada3SDoug Rabson else 540a9148abdSDoug Rabson stat = _seterr_reply(&reply_msg, errp); 541dfdcada3SDoug Rabson 542a9148abdSDoug Rabson if (stat == RPC_SUCCESS) { 543a9148abdSDoug Rabson results = xdrmbuf_getall(&xdrs); 544a9148abdSDoug Rabson if (!AUTH_VALIDATE(auth, xid, 545a9148abdSDoug Rabson &reply_msg.acpted_rply.ar_verf, 546a9148abdSDoug Rabson &results)) { 547a9148abdSDoug Rabson errp->re_status = stat = RPC_AUTHERROR; 548a9148abdSDoug Rabson errp->re_why = AUTH_INVALIDRESP; 549a9148abdSDoug Rabson } else { 550a9148abdSDoug Rabson KASSERT(results, 551a9148abdSDoug Rabson ("auth validated but no result")); 552a9148abdSDoug Rabson *resultsp = results; 553dfdcada3SDoug Rabson } 554dfdcada3SDoug Rabson } /* end successful completion */ 555dfdcada3SDoug Rabson /* 5566244c6e7SPedro F. Giffuni * If unsuccessful AND error is an authentication error 557dfdcada3SDoug Rabson * then refresh credentials and try again, else break 558dfdcada3SDoug Rabson */ 559a9148abdSDoug Rabson else if (stat == RPC_AUTHERROR) 560dfdcada3SDoug Rabson /* maybe our credentials need to be refreshed ... */ 561dfdcada3SDoug Rabson if (nrefreshes > 0 && 562a9148abdSDoug Rabson AUTH_REFRESH(auth, &reply_msg)) { 563dfdcada3SDoug Rabson nrefreshes--; 564a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 565a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 566dfdcada3SDoug Rabson goto call_again; 567dfdcada3SDoug Rabson } 568dfdcada3SDoug Rabson /* end of unsuccessful completion */ 569dfdcada3SDoug Rabson } /* end of valid reply message */ 570dfdcada3SDoug Rabson else { 571a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTDECODERES; 572dfdcada3SDoug Rabson } 573a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 574a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 575dfdcada3SDoug Rabson out: 576dfdcada3SDoug Rabson mtx_assert(&ct->ct_lock, MA_OWNED); 577dfdcada3SDoug Rabson 578a9148abdSDoug Rabson KASSERT(stat != RPC_SUCCESS || *resultsp, 579a9148abdSDoug Rabson ("RPC_SUCCESS without reply")); 580a9148abdSDoug Rabson 581dfdcada3SDoug Rabson if (mreq) 582dfdcada3SDoug Rabson m_freem(mreq); 583c675522fSDoug Rabson if (cr->cr_mrep) 584c675522fSDoug Rabson m_freem(cr->cr_mrep); 585c675522fSDoug Rabson 586c675522fSDoug Rabson ct->ct_threads--; 587c675522fSDoug Rabson if (ct->ct_closing) 588c675522fSDoug Rabson wakeup(ct); 589dfdcada3SDoug Rabson 590dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 591c675522fSDoug Rabson 592a9148abdSDoug Rabson if (auth && stat != RPC_SUCCESS) 593a9148abdSDoug Rabson AUTH_VALIDATE(auth, xid, NULL, NULL); 594a9148abdSDoug Rabson 595c675522fSDoug Rabson free(cr, M_RPC); 596c675522fSDoug Rabson 597a9148abdSDoug Rabson return (stat); 598dfdcada3SDoug Rabson } 599dfdcada3SDoug Rabson 600dfdcada3SDoug Rabson static void 601dfdcada3SDoug Rabson clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp) 602dfdcada3SDoug Rabson { 603dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 604dfdcada3SDoug Rabson 605dfdcada3SDoug Rabson *errp = ct->ct_error; 606dfdcada3SDoug Rabson } 607dfdcada3SDoug Rabson 608dfdcada3SDoug Rabson static bool_t 609dfdcada3SDoug Rabson clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 610dfdcada3SDoug Rabson { 611dfdcada3SDoug Rabson XDR xdrs; 612dfdcada3SDoug Rabson bool_t dummy; 613dfdcada3SDoug Rabson 614dfdcada3SDoug Rabson xdrs.x_op = XDR_FREE; 615dfdcada3SDoug Rabson dummy = (*xdr_res)(&xdrs, res_ptr); 616dfdcada3SDoug Rabson 617dfdcada3SDoug Rabson return (dummy); 618dfdcada3SDoug Rabson } 619dfdcada3SDoug Rabson 620dfdcada3SDoug Rabson /*ARGSUSED*/ 621dfdcada3SDoug Rabson static void 622dfdcada3SDoug Rabson clnt_vc_abort(CLIENT *cl) 623dfdcada3SDoug Rabson { 624dfdcada3SDoug Rabson } 625dfdcada3SDoug Rabson 626dfdcada3SDoug Rabson static bool_t 627dfdcada3SDoug Rabson clnt_vc_control(CLIENT *cl, u_int request, void *info) 628dfdcada3SDoug Rabson { 629dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *)cl->cl_private; 630dfdcada3SDoug Rabson void *infop = info; 631e2adc47dSRick Macklem SVCXPRT *xprt; 632ab0c29afSRick Macklem uint64_t *p; 633ab0c29afSRick Macklem int error; 634ab0c29afSRick Macklem static u_int thrdnum = 0; 635dfdcada3SDoug Rabson 636dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 637dfdcada3SDoug Rabson 638dfdcada3SDoug Rabson switch (request) { 639dfdcada3SDoug Rabson case CLSET_FD_CLOSE: 640dfdcada3SDoug Rabson ct->ct_closeit = TRUE; 641dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 642dfdcada3SDoug Rabson return (TRUE); 643dfdcada3SDoug Rabson case CLSET_FD_NCLOSE: 644dfdcada3SDoug Rabson ct->ct_closeit = FALSE; 645dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 646dfdcada3SDoug Rabson return (TRUE); 647dfdcada3SDoug Rabson default: 648dfdcada3SDoug Rabson break; 649dfdcada3SDoug Rabson } 650dfdcada3SDoug Rabson 651dfdcada3SDoug Rabson /* for other requests which use info */ 652dfdcada3SDoug Rabson if (info == NULL) { 653dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 654dfdcada3SDoug Rabson return (FALSE); 655dfdcada3SDoug Rabson } 656dfdcada3SDoug Rabson switch (request) { 657dfdcada3SDoug Rabson case CLSET_TIMEOUT: 658dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 659dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 660dfdcada3SDoug Rabson return (FALSE); 661dfdcada3SDoug Rabson } 662dfdcada3SDoug Rabson ct->ct_wait = *(struct timeval *)infop; 663dfdcada3SDoug Rabson break; 664dfdcada3SDoug Rabson case CLGET_TIMEOUT: 665dfdcada3SDoug Rabson *(struct timeval *)infop = ct->ct_wait; 666dfdcada3SDoug Rabson break; 667dfdcada3SDoug Rabson case CLGET_SERVER_ADDR: 668dfdcada3SDoug Rabson (void) memcpy(info, &ct->ct_addr, (size_t)ct->ct_addr.ss_len); 669dfdcada3SDoug Rabson break; 670dfdcada3SDoug Rabson case CLGET_SVC_ADDR: 671dfdcada3SDoug Rabson /* 672dfdcada3SDoug Rabson * Slightly different semantics to userland - we use 673dfdcada3SDoug Rabson * sockaddr instead of netbuf. 674dfdcada3SDoug Rabson */ 675dfdcada3SDoug Rabson memcpy(info, &ct->ct_addr, ct->ct_addr.ss_len); 676dfdcada3SDoug Rabson break; 677dfdcada3SDoug Rabson case CLSET_SVC_ADDR: /* set to new address */ 678dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 679dfdcada3SDoug Rabson return (FALSE); 680dfdcada3SDoug Rabson case CLGET_XID: 681dfdcada3SDoug Rabson *(uint32_t *)info = ct->ct_xid; 682dfdcada3SDoug Rabson break; 683dfdcada3SDoug Rabson case CLSET_XID: 684dfdcada3SDoug Rabson /* This will set the xid of the NEXT call */ 685dfdcada3SDoug Rabson /* decrement by 1 as clnt_vc_call() increments once */ 686dfdcada3SDoug Rabson ct->ct_xid = *(uint32_t *)info - 1; 687dfdcada3SDoug Rabson break; 688dfdcada3SDoug Rabson case CLGET_VERS: 689dfdcada3SDoug Rabson /* 690dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 691dfdcada3SDoug Rabson * the version number field is the fifth field from the 6926244c6e7SPedro F. Giffuni * beginning of the RPC header. MUST be changed if the 693dfdcada3SDoug Rabson * call_struct is changed 694dfdcada3SDoug Rabson */ 695dfdcada3SDoug Rabson *(uint32_t *)info = 696dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(ct->ct_mcallc + 697dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT)); 698dfdcada3SDoug Rabson break; 699dfdcada3SDoug Rabson 700dfdcada3SDoug Rabson case CLSET_VERS: 701dfdcada3SDoug Rabson *(uint32_t *)(void *)(ct->ct_mcallc + 702dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT) = 703dfdcada3SDoug Rabson htonl(*(uint32_t *)info); 704dfdcada3SDoug Rabson break; 705dfdcada3SDoug Rabson 706dfdcada3SDoug Rabson case CLGET_PROG: 707dfdcada3SDoug Rabson /* 708dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 709dfdcada3SDoug Rabson * the program number field is the fourth field from the 7106244c6e7SPedro F. Giffuni * beginning of the RPC header. MUST be changed if the 711dfdcada3SDoug Rabson * call_struct is changed 712dfdcada3SDoug Rabson */ 713dfdcada3SDoug Rabson *(uint32_t *)info = 714dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(ct->ct_mcallc + 715dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT)); 716dfdcada3SDoug Rabson break; 717dfdcada3SDoug Rabson 718dfdcada3SDoug Rabson case CLSET_PROG: 719dfdcada3SDoug Rabson *(uint32_t *)(void *)(ct->ct_mcallc + 720dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT) = 721dfdcada3SDoug Rabson htonl(*(uint32_t *)info); 722dfdcada3SDoug Rabson break; 723dfdcada3SDoug Rabson 724dfdcada3SDoug Rabson case CLSET_WAITCHAN: 725a9148abdSDoug Rabson ct->ct_waitchan = (const char *)info; 726dfdcada3SDoug Rabson break; 727dfdcada3SDoug Rabson 728dfdcada3SDoug Rabson case CLGET_WAITCHAN: 729dfdcada3SDoug Rabson *(const char **) info = ct->ct_waitchan; 730dfdcada3SDoug Rabson break; 731dfdcada3SDoug Rabson 732dfdcada3SDoug Rabson case CLSET_INTERRUPTIBLE: 733dfdcada3SDoug Rabson if (*(int *) info) 7343b14c753SJohn Baldwin ct->ct_waitflag = PCATCH; 735dfdcada3SDoug Rabson else 736dfdcada3SDoug Rabson ct->ct_waitflag = 0; 737dfdcada3SDoug Rabson break; 738dfdcada3SDoug Rabson 739dfdcada3SDoug Rabson case CLGET_INTERRUPTIBLE: 740dfdcada3SDoug Rabson if (ct->ct_waitflag) 741dfdcada3SDoug Rabson *(int *) info = TRUE; 742dfdcada3SDoug Rabson else 743dfdcada3SDoug Rabson *(int *) info = FALSE; 744dfdcada3SDoug Rabson break; 745dfdcada3SDoug Rabson 746e2adc47dSRick Macklem case CLSET_BACKCHANNEL: 747e2adc47dSRick Macklem xprt = (SVCXPRT *)info; 748e2adc47dSRick Macklem if (ct->ct_backchannelxprt == NULL) { 7494ba444deSRick Macklem SVC_ACQUIRE(xprt); 750e2adc47dSRick Macklem xprt->xp_p2 = ct; 751ab0c29afSRick Macklem if (ct->ct_sslrefno != 0) 752ab0c29afSRick Macklem xprt->xp_tls = RPCTLS_FLAGS_HANDSHAKE; 753e2adc47dSRick Macklem ct->ct_backchannelxprt = xprt; 754e2adc47dSRick Macklem } 755e2adc47dSRick Macklem break; 756e2adc47dSRick Macklem 757ab0c29afSRick Macklem case CLSET_TLS: 758ab0c29afSRick Macklem p = (uint64_t *)info; 759ab0c29afSRick Macklem ct->ct_sslsec = *p++; 760ab0c29afSRick Macklem ct->ct_sslusec = *p++; 761ab0c29afSRick Macklem ct->ct_sslrefno = *p; 762ab0c29afSRick Macklem if (ct->ct_sslrefno != RPCTLS_REFNO_HANDSHAKE) { 7634ba444deSRick Macklem /* cl ref cnt is released by clnt_vc_dotlsupcall(). */ 7644ba444deSRick Macklem CLNT_ACQUIRE(cl); 765ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 766ab0c29afSRick Macklem /* Start the kthread that handles upcalls. */ 7674ba444deSRick Macklem error = kthread_add(clnt_vc_dotlsupcall, cl, 768ab0c29afSRick Macklem NULL, NULL, 0, 0, "krpctls%u", thrdnum++); 769ab0c29afSRick Macklem if (error != 0) 770ab0c29afSRick Macklem panic("Can't add KRPC thread error %d", error); 771ab0c29afSRick Macklem } else 772ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 773ab0c29afSRick Macklem return (TRUE); 774ab0c29afSRick Macklem 775ab0c29afSRick Macklem case CLSET_BLOCKRCV: 776ab0c29afSRick Macklem if (*(int *) info) { 777ab0c29afSRick Macklem ct->ct_rcvstate &= ~RPCRCVSTATE_NORMAL; 778ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_TLSHANDSHAKE; 779ab0c29afSRick Macklem } else { 780ab0c29afSRick Macklem ct->ct_rcvstate &= ~RPCRCVSTATE_TLSHANDSHAKE; 781ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_NORMAL; 782ab0c29afSRick Macklem } 783ab0c29afSRick Macklem break; 784ab0c29afSRick Macklem 785dfdcada3SDoug Rabson default: 786dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 787dfdcada3SDoug Rabson return (FALSE); 788dfdcada3SDoug Rabson } 789dfdcada3SDoug Rabson 790dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 791dfdcada3SDoug Rabson return (TRUE); 792dfdcada3SDoug Rabson } 793dfdcada3SDoug Rabson 794dfdcada3SDoug Rabson static void 795a9148abdSDoug Rabson clnt_vc_close(CLIENT *cl) 796dfdcada3SDoug Rabson { 797dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 798c675522fSDoug Rabson struct ct_request *cr; 799dfdcada3SDoug Rabson 800dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 801dfdcada3SDoug Rabson 802a9148abdSDoug Rabson if (ct->ct_closed) { 803a9148abdSDoug Rabson mtx_unlock(&ct->ct_lock); 804a9148abdSDoug Rabson return; 805a9148abdSDoug Rabson } 806a9148abdSDoug Rabson 807a9148abdSDoug Rabson if (ct->ct_closing) { 808a9148abdSDoug Rabson while (ct->ct_closing) 809a9148abdSDoug Rabson msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 810a9148abdSDoug Rabson KASSERT(ct->ct_closed, ("client should be closed")); 811a9148abdSDoug Rabson mtx_unlock(&ct->ct_lock); 812a9148abdSDoug Rabson return; 813a9148abdSDoug Rabson } 814a9148abdSDoug Rabson 815dfdcada3SDoug Rabson if (ct->ct_socket) { 81674fb0ba7SJohn Baldwin ct->ct_closing = TRUE; 81774fb0ba7SJohn Baldwin mtx_unlock(&ct->ct_lock); 81874fb0ba7SJohn Baldwin 819e205fd31SGleb Smirnoff SOCK_RECVBUF_LOCK(ct->ct_socket); 820ab0c29afSRick Macklem if (ct->ct_socket->so_rcv.sb_upcall != NULL) { 82174fb0ba7SJohn Baldwin soupcall_clear(ct->ct_socket, SO_RCV); 8223144f812SRick Macklem clnt_vc_upcallsdone(ct); 823ab0c29afSRick Macklem } 824e205fd31SGleb Smirnoff SOCK_RECVBUF_UNLOCK(ct->ct_socket); 825dfdcada3SDoug Rabson 826c675522fSDoug Rabson /* 827c675522fSDoug Rabson * Abort any pending requests and wait until everyone 828c675522fSDoug Rabson * has finished with clnt_vc_call. 829c675522fSDoug Rabson */ 83074fb0ba7SJohn Baldwin mtx_lock(&ct->ct_lock); 831c675522fSDoug Rabson TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 832c675522fSDoug Rabson cr->cr_xid = 0; 833c675522fSDoug Rabson cr->cr_error = ESHUTDOWN; 834c675522fSDoug Rabson wakeup(cr); 835c675522fSDoug Rabson } 836c675522fSDoug Rabson 837c675522fSDoug Rabson while (ct->ct_threads) 838c675522fSDoug Rabson msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 839a9148abdSDoug Rabson } 840dfdcada3SDoug Rabson 841a9148abdSDoug Rabson ct->ct_closing = FALSE; 842a9148abdSDoug Rabson ct->ct_closed = TRUE; 843ab0c29afSRick Macklem wakeup(&ct->ct_sslrefno); 844a9148abdSDoug Rabson mtx_unlock(&ct->ct_lock); 845a9148abdSDoug Rabson wakeup(ct); 846a9148abdSDoug Rabson } 847a9148abdSDoug Rabson 848a9148abdSDoug Rabson static void 849a9148abdSDoug Rabson clnt_vc_destroy(CLIENT *cl) 850a9148abdSDoug Rabson { 851a9148abdSDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 852d9f9a73aSGleb Smirnoff struct socket *so; 853e2adc47dSRick Macklem SVCXPRT *xprt; 854ab0c29afSRick Macklem uint32_t reterr; 855a9148abdSDoug Rabson 856a9148abdSDoug Rabson clnt_vc_close(cl); 857a9148abdSDoug Rabson 858a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 859e2adc47dSRick Macklem xprt = ct->ct_backchannelxprt; 860e2adc47dSRick Macklem ct->ct_backchannelxprt = NULL; 861e2adc47dSRick Macklem if (xprt != NULL) { 862e2adc47dSRick Macklem mtx_unlock(&ct->ct_lock); /* To avoid a LOR. */ 863e2adc47dSRick Macklem sx_xlock(&xprt->xp_lock); 864e2adc47dSRick Macklem mtx_lock(&ct->ct_lock); 865e2adc47dSRick Macklem xprt->xp_p2 = NULL; 86634f1fddbSRick Macklem sx_xunlock(&xprt->xp_lock); 8674ba444deSRick Macklem SVC_RELEASE(xprt); 868e2adc47dSRick Macklem } 869a9148abdSDoug Rabson 870ab0c29afSRick Macklem /* Wait for the upcall kthread to terminate. */ 871ab0c29afSRick Macklem while ((ct->ct_rcvstate & RPCRCVSTATE_UPCALLTHREAD) != 0) 872ab0c29afSRick Macklem msleep(&ct->ct_sslrefno, &ct->ct_lock, 0, 873ab0c29afSRick Macklem "clntvccl", hz); 874dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 875dfdcada3SDoug Rabson mtx_destroy(&ct->ct_lock); 876d9f9a73aSGleb Smirnoff 877d9f9a73aSGleb Smirnoff so = ct->ct_closeit ? ct->ct_socket : NULL; 878dfdcada3SDoug Rabson if (so) { 879ab0c29afSRick Macklem if (ct->ct_sslrefno != 0) { 880ab0c29afSRick Macklem /* 881ab0c29afSRick Macklem * If the TLS handshake is in progress, the upcall 882ab0c29afSRick Macklem * will fail, but the socket should be closed by the 883ab0c29afSRick Macklem * daemon, since the connect upcall has just failed. 884ab0c29afSRick Macklem */ 885ab0c29afSRick Macklem if (ct->ct_sslrefno != RPCTLS_REFNO_HANDSHAKE) { 886ab0c29afSRick Macklem /* 887ab0c29afSRick Macklem * If the upcall fails, the socket has 888ab0c29afSRick Macklem * probably been closed via the rpctlscd 889ab0c29afSRick Macklem * daemon having crashed or been 890ab0c29afSRick Macklem * restarted, so ignore return stat. 891ab0c29afSRick Macklem */ 89277bc5890SWarner Losh rpctls_cl_disconnect(ct->ct_sslsec, 893ab0c29afSRick Macklem ct->ct_sslusec, ct->ct_sslrefno, 894ab0c29afSRick Macklem &reterr); 895ab0c29afSRick Macklem } 896ab0c29afSRick Macklem /* Must sorele() to get rid of reference. */ 897ab0c29afSRick Macklem CURVNET_SET(so->so_vnet); 898ab0c29afSRick Macklem sorele(so); 899ab0c29afSRick Macklem CURVNET_RESTORE(); 900ab0c29afSRick Macklem } else { 901dfdcada3SDoug Rabson soshutdown(so, SHUT_WR); 902dfdcada3SDoug Rabson soclose(so); 903dfdcada3SDoug Rabson } 904ab0c29afSRick Macklem } 9054302e8b6SRick Macklem m_freem(ct->ct_record); 9064302e8b6SRick Macklem m_freem(ct->ct_raw); 907dfdcada3SDoug Rabson mem_free(ct, sizeof(struct ct_data)); 9080c2222baSPedro F. Giffuni if (cl->cl_netid && cl->cl_netid[0]) 9090c2222baSPedro F. Giffuni mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 9100c2222baSPedro F. Giffuni if (cl->cl_tp && cl->cl_tp[0]) 9110c2222baSPedro F. Giffuni mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 912dfdcada3SDoug Rabson mem_free(cl, sizeof(CLIENT)); 913dfdcada3SDoug Rabson } 914dfdcada3SDoug Rabson 915dfdcada3SDoug Rabson /* 916dfdcada3SDoug Rabson * Make sure that the time is not garbage. -1 value is disallowed. 917dfdcada3SDoug Rabson * Note this is different from time_not_ok in clnt_dg.c 918dfdcada3SDoug Rabson */ 919dfdcada3SDoug Rabson static bool_t 920dfdcada3SDoug Rabson time_not_ok(struct timeval *t) 921dfdcada3SDoug Rabson { 922dfdcada3SDoug Rabson return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 923dfdcada3SDoug Rabson t->tv_usec <= -1 || t->tv_usec > 1000000); 924dfdcada3SDoug Rabson } 925dfdcada3SDoug Rabson 92674fb0ba7SJohn Baldwin int 927dfdcada3SDoug Rabson clnt_vc_soupcall(struct socket *so, void *arg, int waitflag) 928dfdcada3SDoug Rabson { 929dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) arg; 930dfdcada3SDoug Rabson struct uio uio; 9310b4f2ab0SRick Macklem struct mbuf *m, *m2; 932dfdcada3SDoug Rabson struct ct_request *cr; 933dfdcada3SDoug Rabson int error, rcvflag, foundreq; 934e2adc47dSRick Macklem uint32_t xid_plus_direction[2], header; 935e2adc47dSRick Macklem SVCXPRT *xprt; 936e2adc47dSRick Macklem struct cf_conn *cd; 9374302e8b6SRick Macklem u_int rawlen; 938ab0c29afSRick Macklem struct cmsghdr *cmsg; 939ab0c29afSRick Macklem struct tls_get_record tgr; 940ab0c29afSRick Macklem 941ab0c29afSRick Macklem /* 942ab0c29afSRick Macklem * RPC-over-TLS needs to block reception during 943ab0c29afSRick Macklem * upcalls since the upcall will be doing I/O on 944ab0c29afSRick Macklem * the socket via openssl library calls. 945ab0c29afSRick Macklem */ 946ab0c29afSRick Macklem mtx_lock(&ct->ct_lock); 947ab0c29afSRick Macklem if ((ct->ct_rcvstate & (RPCRCVSTATE_NORMAL | 948ab0c29afSRick Macklem RPCRCVSTATE_NONAPPDATA)) == 0) { 949ab0c29afSRick Macklem /* Mark that a socket upcall needs to be done. */ 950ab0c29afSRick Macklem if ((ct->ct_rcvstate & (RPCRCVSTATE_UPCALLNEEDED | 951ab0c29afSRick Macklem RPCRCVSTATE_UPCALLINPROG)) != 0) 952ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_SOUPCALLNEEDED; 953ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 954ab0c29afSRick Macklem return (SU_OK); 955ab0c29afSRick Macklem } 956ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 957dfdcada3SDoug Rabson 9584302e8b6SRick Macklem /* 9594302e8b6SRick Macklem * If another thread is already here, it must be in 9604302e8b6SRick Macklem * soreceive(), so just return to avoid races with it. 961e205fd31SGleb Smirnoff * ct_upcallrefs is protected by the socket receive buffer lock 9624302e8b6SRick Macklem * which is held in this function, except when 9634302e8b6SRick Macklem * soreceive() is called. 9644302e8b6SRick Macklem */ 9654302e8b6SRick Macklem if (ct->ct_upcallrefs > 0) 9664302e8b6SRick Macklem return (SU_OK); 9673144f812SRick Macklem ct->ct_upcallrefs++; 9684302e8b6SRick Macklem 9694302e8b6SRick Macklem /* 9704302e8b6SRick Macklem * Read as much as possible off the socket and link it 9714302e8b6SRick Macklem * onto ct_raw. 9724302e8b6SRick Macklem */ 9734302e8b6SRick Macklem for (;;) { 9744302e8b6SRick Macklem uio.uio_resid = 1000000000; 975dfdcada3SDoug Rabson uio.uio_td = curthread; 9764302e8b6SRick Macklem m2 = m = NULL; 977dfdcada3SDoug Rabson rcvflag = MSG_DONTWAIT | MSG_SOCALLBCK; 978ab0c29afSRick Macklem if (ct->ct_sslrefno != 0 && (ct->ct_rcvstate & 9790b4f2ab0SRick Macklem RPCRCVSTATE_NORMAL) != 0) 980ab0c29afSRick Macklem rcvflag |= MSG_TLSAPPDATA; 981e205fd31SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 9820b4f2ab0SRick Macklem error = soreceive(so, NULL, &uio, &m, &m2, &rcvflag); 983e205fd31SGleb Smirnoff SOCK_RECVBUF_LOCK(so); 984dfdcada3SDoug Rabson 9854302e8b6SRick Macklem if (error == EWOULDBLOCK) { 986dfdcada3SDoug Rabson /* 9874302e8b6SRick Macklem * We must re-test for readability after 9884302e8b6SRick Macklem * taking the lock to protect us in the case 9894302e8b6SRick Macklem * where a new packet arrives on the socket 9904302e8b6SRick Macklem * after our call to soreceive fails with 9914302e8b6SRick Macklem * EWOULDBLOCK. 992dfdcada3SDoug Rabson */ 9934302e8b6SRick Macklem error = 0; 9944302e8b6SRick Macklem if (!soreadable(so)) 9954302e8b6SRick Macklem break; 9964302e8b6SRick Macklem continue; 9974302e8b6SRick Macklem } 9984302e8b6SRick Macklem if (error == 0 && m == NULL) { 999dfdcada3SDoug Rabson /* 1000dfdcada3SDoug Rabson * We must have got EOF trying 1001dfdcada3SDoug Rabson * to read from the stream. 1002dfdcada3SDoug Rabson */ 1003dfdcada3SDoug Rabson error = ECONNRESET; 1004dfdcada3SDoug Rabson } 1005ab0c29afSRick Macklem 1006ab0c29afSRick Macklem /* 10070b4f2ab0SRick Macklem * A return of ENXIO indicates that there is an 10080b4f2ab0SRick Macklem * alert record at the head of the 1009ab0c29afSRick Macklem * socket's receive queue, for TLS connections. 1010ab0c29afSRick Macklem * This record needs to be handled in userland 1011ab0c29afSRick Macklem * via an SSL_read() call, so do an upcall to the daemon. 1012ab0c29afSRick Macklem */ 1013ab0c29afSRick Macklem if (ct->ct_sslrefno != 0 && error == ENXIO) { 1014ab0c29afSRick Macklem /* Disable reception, marking an upcall needed. */ 1015ab0c29afSRick Macklem mtx_lock(&ct->ct_lock); 1016ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_UPCALLNEEDED; 1017ab0c29afSRick Macklem /* 1018ab0c29afSRick Macklem * If an upcall in needed, wake up the kthread 1019ab0c29afSRick Macklem * that runs clnt_vc_dotlsupcall(). 1020ab0c29afSRick Macklem */ 1021ab0c29afSRick Macklem wakeup(&ct->ct_sslrefno); 1022ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 1023ab0c29afSRick Macklem break; 1024ab0c29afSRick Macklem } 10254302e8b6SRick Macklem if (error != 0) 1026dfdcada3SDoug Rabson break; 10274302e8b6SRick Macklem 1028ab0c29afSRick Macklem /* Process any record header(s). */ 1029ab0c29afSRick Macklem if (m2 != NULL) { 1030ab0c29afSRick Macklem cmsg = mtod(m2, struct cmsghdr *); 1031ab0c29afSRick Macklem if (cmsg->cmsg_type == TLS_GET_RECORD && 1032ab0c29afSRick Macklem cmsg->cmsg_len == CMSG_LEN(sizeof(tgr))) { 1033ab0c29afSRick Macklem memcpy(&tgr, CMSG_DATA(cmsg), sizeof(tgr)); 1034ab0c29afSRick Macklem /* 10350b4f2ab0SRick Macklem * TLS_RLTYPE_ALERT records should be handled 10360b4f2ab0SRick Macklem * since soreceive() would have returned 10370b4f2ab0SRick Macklem * ENXIO. Just throw any other 10380b4f2ab0SRick Macklem * non-TLS_RLTYPE_APP records away. 1039ab0c29afSRick Macklem */ 1040ab0c29afSRick Macklem if (tgr.tls_type != TLS_RLTYPE_APP) { 1041ab0c29afSRick Macklem m_freem(m); 1042ab0c29afSRick Macklem m_free(m2); 1043ab0c29afSRick Macklem mtx_lock(&ct->ct_lock); 1044ab0c29afSRick Macklem ct->ct_rcvstate &= 1045ab0c29afSRick Macklem ~RPCRCVSTATE_NONAPPDATA; 1046ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_NORMAL; 1047ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 1048ab0c29afSRick Macklem continue; 1049ab0c29afSRick Macklem } 1050ab0c29afSRick Macklem } 1051ab0c29afSRick Macklem m_free(m2); 1052ab0c29afSRick Macklem } 1053ab0c29afSRick Macklem 10544302e8b6SRick Macklem if (ct->ct_raw != NULL) 10554302e8b6SRick Macklem m_last(ct->ct_raw)->m_next = m; 10564302e8b6SRick Macklem else 10574302e8b6SRick Macklem ct->ct_raw = m; 1058dfdcada3SDoug Rabson } 10594302e8b6SRick Macklem rawlen = m_length(ct->ct_raw, NULL); 10604302e8b6SRick Macklem 10614302e8b6SRick Macklem /* Now, process as much of ct_raw as possible. */ 10624302e8b6SRick Macklem for (;;) { 10634302e8b6SRick Macklem /* 10644302e8b6SRick Macklem * If ct_record_resid is zero, we are waiting for a 10654302e8b6SRick Macklem * record mark. 10664302e8b6SRick Macklem */ 10674302e8b6SRick Macklem if (ct->ct_record_resid == 0) { 10684302e8b6SRick Macklem if (rawlen < sizeof(uint32_t)) 10694302e8b6SRick Macklem break; 10704302e8b6SRick Macklem m_copydata(ct->ct_raw, 0, sizeof(uint32_t), 10714302e8b6SRick Macklem (char *)&header); 1072dfdcada3SDoug Rabson header = ntohl(header); 1073dfdcada3SDoug Rabson ct->ct_record_resid = header & 0x7fffffff; 1074dfdcada3SDoug Rabson ct->ct_record_eor = ((header & 0x80000000) != 0); 10754302e8b6SRick Macklem m_adj(ct->ct_raw, sizeof(uint32_t)); 10764302e8b6SRick Macklem rawlen -= sizeof(uint32_t); 1077dfdcada3SDoug Rabson } else { 1078dfdcada3SDoug Rabson /* 10794302e8b6SRick Macklem * Move as much of the record as possible to 10804302e8b6SRick Macklem * ct_record. 1081a9148abdSDoug Rabson */ 10824302e8b6SRick Macklem if (rawlen == 0) 10833144f812SRick Macklem break; 10844302e8b6SRick Macklem if (rawlen <= ct->ct_record_resid) { 10854302e8b6SRick Macklem if (ct->ct_record != NULL) 10864302e8b6SRick Macklem m_last(ct->ct_record)->m_next = 10874302e8b6SRick Macklem ct->ct_raw; 1088dfdcada3SDoug Rabson else 10894302e8b6SRick Macklem ct->ct_record = ct->ct_raw; 10904302e8b6SRick Macklem ct->ct_raw = NULL; 10914302e8b6SRick Macklem ct->ct_record_resid -= rawlen; 10924302e8b6SRick Macklem rawlen = 0; 10934302e8b6SRick Macklem } else { 10944302e8b6SRick Macklem m = m_split(ct->ct_raw, ct->ct_record_resid, 10954302e8b6SRick Macklem M_NOWAIT); 10964302e8b6SRick Macklem if (m == NULL) 10974302e8b6SRick Macklem break; 10984302e8b6SRick Macklem if (ct->ct_record != NULL) 10994302e8b6SRick Macklem m_last(ct->ct_record)->m_next = 11004302e8b6SRick Macklem ct->ct_raw; 11014302e8b6SRick Macklem else 11024302e8b6SRick Macklem ct->ct_record = ct->ct_raw; 11034302e8b6SRick Macklem rawlen -= ct->ct_record_resid; 11044302e8b6SRick Macklem ct->ct_record_resid = 0; 11054302e8b6SRick Macklem ct->ct_raw = m; 11064302e8b6SRick Macklem } 11074302e8b6SRick Macklem if (ct->ct_record_resid > 0) 11084302e8b6SRick Macklem break; 1109dfdcada3SDoug Rabson 1110dfdcada3SDoug Rabson /* 1111dfdcada3SDoug Rabson * If we have the entire record, see if we can 1112dfdcada3SDoug Rabson * match it to a request. 1113dfdcada3SDoug Rabson */ 11144302e8b6SRick Macklem if (ct->ct_record_eor) { 1115dfdcada3SDoug Rabson /* 1116dfdcada3SDoug Rabson * The XID is in the first uint32_t of 1117e2adc47dSRick Macklem * the reply and the message direction 1118e2adc47dSRick Macklem * is the second one. 1119dfdcada3SDoug Rabson */ 1120e2adc47dSRick Macklem if (ct->ct_record->m_len < 1121e2adc47dSRick Macklem sizeof(xid_plus_direction) && 11225e8eb3cdSRick Macklem m_length(ct->ct_record, NULL) < 1123e2adc47dSRick Macklem sizeof(xid_plus_direction)) { 11244302e8b6SRick Macklem /* 11254302e8b6SRick Macklem * What to do now? 11264302e8b6SRick Macklem * The data in the TCP stream is 11274302e8b6SRick Macklem * corrupted such that there is no 11284302e8b6SRick Macklem * valid RPC message to parse. 11294302e8b6SRick Macklem * I think it best to close this 11304302e8b6SRick Macklem * connection and allow 1131b94b9a80SRick Macklem * clnt_reconnect_call() to try 11324302e8b6SRick Macklem * and establish a new one. 11334302e8b6SRick Macklem */ 11344302e8b6SRick Macklem printf("clnt_vc_soupcall: " 11354302e8b6SRick Macklem "connection data corrupted\n"); 11364302e8b6SRick Macklem error = ECONNRESET; 11374302e8b6SRick Macklem goto wakeup_all; 11385e8eb3cdSRick Macklem } 1139e2adc47dSRick Macklem m_copydata(ct->ct_record, 0, 1140e2adc47dSRick Macklem sizeof(xid_plus_direction), 1141e2adc47dSRick Macklem (char *)xid_plus_direction); 1142e2adc47dSRick Macklem xid_plus_direction[0] = 1143e2adc47dSRick Macklem ntohl(xid_plus_direction[0]); 1144e2adc47dSRick Macklem xid_plus_direction[1] = 1145e2adc47dSRick Macklem ntohl(xid_plus_direction[1]); 1146e2adc47dSRick Macklem /* Check message direction. */ 1147e2adc47dSRick Macklem if (xid_plus_direction[1] == CALL) { 1148e2adc47dSRick Macklem /* This is a backchannel request. */ 1149e2adc47dSRick Macklem mtx_lock(&ct->ct_lock); 1150e2adc47dSRick Macklem xprt = ct->ct_backchannelxprt; 1151e2adc47dSRick Macklem if (xprt == NULL) { 1152e2adc47dSRick Macklem mtx_unlock(&ct->ct_lock); 1153e2adc47dSRick Macklem /* Just throw it away. */ 1154e2adc47dSRick Macklem m_freem(ct->ct_record); 1155e2adc47dSRick Macklem ct->ct_record = NULL; 1156e2adc47dSRick Macklem } else { 1157e2adc47dSRick Macklem cd = (struct cf_conn *) 1158e2adc47dSRick Macklem xprt->xp_p1; 1159e2adc47dSRick Macklem m2 = cd->mreq; 1160e2adc47dSRick Macklem /* 1161e2adc47dSRick Macklem * The requests are chained 1162e2adc47dSRick Macklem * in the m_nextpkt list. 1163e2adc47dSRick Macklem */ 1164e2adc47dSRick Macklem while (m2 != NULL && 1165e2adc47dSRick Macklem m2->m_nextpkt != NULL) 1166e2adc47dSRick Macklem /* Find end of list. */ 1167e2adc47dSRick Macklem m2 = m2->m_nextpkt; 1168e2adc47dSRick Macklem if (m2 != NULL) 1169e2adc47dSRick Macklem m2->m_nextpkt = 1170e2adc47dSRick Macklem ct->ct_record; 1171e2adc47dSRick Macklem else 1172e2adc47dSRick Macklem cd->mreq = 1173e2adc47dSRick Macklem ct->ct_record; 1174e2adc47dSRick Macklem ct->ct_record->m_nextpkt = 1175e2adc47dSRick Macklem NULL; 1176e2adc47dSRick Macklem ct->ct_record = NULL; 1177e2adc47dSRick Macklem xprt_active(xprt); 1178e2adc47dSRick Macklem mtx_unlock(&ct->ct_lock); 1179e2adc47dSRick Macklem } 1180e2adc47dSRick Macklem } else { 1181dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 1182dfdcada3SDoug Rabson foundreq = 0; 1183e2adc47dSRick Macklem TAILQ_FOREACH(cr, &ct->ct_pending, 1184e2adc47dSRick Macklem cr_link) { 1185e2adc47dSRick Macklem if (cr->cr_xid == 1186e2adc47dSRick Macklem xid_plus_direction[0]) { 1187dfdcada3SDoug Rabson /* 1188dfdcada3SDoug Rabson * This one 1189c675522fSDoug Rabson * matches. We leave 1190c675522fSDoug Rabson * the reply mbuf in 1191dfdcada3SDoug Rabson * cr->cr_mrep. Set 1192dfdcada3SDoug Rabson * the XID to zero so 1193c675522fSDoug Rabson * that we will ignore 1194e2adc47dSRick Macklem * any duplicated 1195c675522fSDoug Rabson * replies. 1196dfdcada3SDoug Rabson */ 1197dfdcada3SDoug Rabson cr->cr_xid = 0; 1198e2adc47dSRick Macklem cr->cr_mrep = 1199e2adc47dSRick Macklem ct->ct_record; 1200dfdcada3SDoug Rabson cr->cr_error = 0; 1201dfdcada3SDoug Rabson foundreq = 1; 1202dfdcada3SDoug Rabson wakeup(cr); 1203dfdcada3SDoug Rabson break; 1204dfdcada3SDoug Rabson } 1205dfdcada3SDoug Rabson } 1206dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 1207dfdcada3SDoug Rabson 1208dfdcada3SDoug Rabson if (!foundreq) 1209dfdcada3SDoug Rabson m_freem(ct->ct_record); 1210dfdcada3SDoug Rabson ct->ct_record = NULL; 1211dfdcada3SDoug Rabson } 1212dfdcada3SDoug Rabson } 1213e2adc47dSRick Macklem } 12144302e8b6SRick Macklem } 12154302e8b6SRick Macklem 12164302e8b6SRick Macklem if (error != 0) { 12174302e8b6SRick Macklem wakeup_all: 12184302e8b6SRick Macklem /* 12194302e8b6SRick Macklem * This socket is broken, so mark that it cannot 12204302e8b6SRick Macklem * receive and fail all RPCs waiting for a reply 12214302e8b6SRick Macklem * on it, so that they will be retried on a new 12224302e8b6SRick Macklem * TCP connection created by clnt_reconnect_X(). 12234302e8b6SRick Macklem */ 12244302e8b6SRick Macklem mtx_lock(&ct->ct_lock); 12254302e8b6SRick Macklem ct->ct_error.re_status = RPC_CANTRECV; 12264302e8b6SRick Macklem ct->ct_error.re_errno = error; 12274302e8b6SRick Macklem TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 12284302e8b6SRick Macklem cr->cr_error = error; 12294302e8b6SRick Macklem wakeup(cr); 12304302e8b6SRick Macklem } 12314302e8b6SRick Macklem mtx_unlock(&ct->ct_lock); 12324302e8b6SRick Macklem } 12334302e8b6SRick Macklem 12343144f812SRick Macklem ct->ct_upcallrefs--; 12353144f812SRick Macklem if (ct->ct_upcallrefs < 0) 12363144f812SRick Macklem panic("rpcvc upcall refcnt"); 12373144f812SRick Macklem if (ct->ct_upcallrefs == 0) 12383144f812SRick Macklem wakeup(&ct->ct_upcallrefs); 123974fb0ba7SJohn Baldwin return (SU_OK); 1240dfdcada3SDoug Rabson } 12413144f812SRick Macklem 12423144f812SRick Macklem /* 12433144f812SRick Macklem * Wait for all upcalls in progress to complete. 12443144f812SRick Macklem */ 12453144f812SRick Macklem static void 12463144f812SRick Macklem clnt_vc_upcallsdone(struct ct_data *ct) 12473144f812SRick Macklem { 12483144f812SRick Macklem 1249e205fd31SGleb Smirnoff SOCK_RECVBUF_LOCK_ASSERT(ct->ct_socket); 12503144f812SRick Macklem 12513144f812SRick Macklem while (ct->ct_upcallrefs > 0) 12523144f812SRick Macklem (void) msleep(&ct->ct_upcallrefs, 12533144f812SRick Macklem SOCKBUF_MTX(&ct->ct_socket->so_rcv), 0, "rpcvcup", 0); 12543144f812SRick Macklem } 1255ab0c29afSRick Macklem 1256ab0c29afSRick Macklem /* 1257ab0c29afSRick Macklem * Do a TLS upcall to the rpctlscd daemon, as required. 1258ab0c29afSRick Macklem * This function runs as a kthread. 1259ab0c29afSRick Macklem */ 1260ab0c29afSRick Macklem static void 1261ab0c29afSRick Macklem clnt_vc_dotlsupcall(void *data) 1262ab0c29afSRick Macklem { 12634ba444deSRick Macklem CLIENT *cl = (CLIENT *)data; 12644ba444deSRick Macklem struct ct_data *ct = (struct ct_data *)cl->cl_private; 1265ab0c29afSRick Macklem enum clnt_stat ret; 1266ab0c29afSRick Macklem uint32_t reterr; 1267ab0c29afSRick Macklem 1268b2ff4cb1SGleb Smirnoff CURVNET_SET(ct->ct_socket->so_vnet); 1269ab0c29afSRick Macklem mtx_lock(&ct->ct_lock); 1270ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_UPCALLTHREAD; 1271ab0c29afSRick Macklem while (!ct->ct_closed) { 1272ab0c29afSRick Macklem if ((ct->ct_rcvstate & RPCRCVSTATE_UPCALLNEEDED) != 0) { 1273ab0c29afSRick Macklem ct->ct_rcvstate &= ~RPCRCVSTATE_UPCALLNEEDED; 1274ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_UPCALLINPROG; 1275ab0c29afSRick Macklem if (ct->ct_sslrefno != 0 && ct->ct_sslrefno != 1276ab0c29afSRick Macklem RPCTLS_REFNO_HANDSHAKE) { 1277ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 1278ab0c29afSRick Macklem ret = rpctls_cl_handlerecord(ct->ct_sslsec, 1279ab0c29afSRick Macklem ct->ct_sslusec, ct->ct_sslrefno, &reterr); 1280ab0c29afSRick Macklem mtx_lock(&ct->ct_lock); 1281ab0c29afSRick Macklem } 1282ab0c29afSRick Macklem ct->ct_rcvstate &= ~RPCRCVSTATE_UPCALLINPROG; 1283ab0c29afSRick Macklem if (ret == RPC_SUCCESS && reterr == RPCTLSERR_OK) 1284ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_NORMAL; 1285ab0c29afSRick Macklem else 1286ab0c29afSRick Macklem ct->ct_rcvstate |= RPCRCVSTATE_NONAPPDATA; 1287ab0c29afSRick Macklem wakeup(&ct->ct_rcvstate); 1288ab0c29afSRick Macklem } 1289ab0c29afSRick Macklem if ((ct->ct_rcvstate & RPCRCVSTATE_SOUPCALLNEEDED) != 0) { 1290ab0c29afSRick Macklem ct->ct_rcvstate &= ~RPCRCVSTATE_SOUPCALLNEEDED; 1291ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 1292e205fd31SGleb Smirnoff SOCK_RECVBUF_LOCK(ct->ct_socket); 1293ab0c29afSRick Macklem clnt_vc_soupcall(ct->ct_socket, ct, M_NOWAIT); 1294e205fd31SGleb Smirnoff SOCK_RECVBUF_UNLOCK(ct->ct_socket); 1295ab0c29afSRick Macklem mtx_lock(&ct->ct_lock); 1296ab0c29afSRick Macklem } 1297ab0c29afSRick Macklem msleep(&ct->ct_sslrefno, &ct->ct_lock, 0, "clntvcdu", hz); 1298ab0c29afSRick Macklem } 1299ab0c29afSRick Macklem ct->ct_rcvstate &= ~RPCRCVSTATE_UPCALLTHREAD; 1300ab0c29afSRick Macklem wakeup(&ct->ct_sslrefno); 1301ab0c29afSRick Macklem mtx_unlock(&ct->ct_lock); 13024ba444deSRick Macklem CLNT_RELEASE(cl); 1303b2ff4cb1SGleb Smirnoff CURVNET_RESTORE(); 1304*6a876e97SGleb Smirnoff kthread_exit(); 1305ab0c29afSRick Macklem } 1306