1268115Srmacklem/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ 2268115Srmacklem 3268115Srmacklem/*- 4268115Srmacklem * Copyright (c) 2009, Sun Microsystems, Inc. 5268115Srmacklem * All rights reserved. 6268115Srmacklem * 7268115Srmacklem * Redistribution and use in source and binary forms, with or without 8268115Srmacklem * modification, are permitted provided that the following conditions are met: 9268115Srmacklem * - Redistributions of source code must retain the above copyright notice, 10268115Srmacklem * this list of conditions and the following disclaimer. 11268115Srmacklem * - Redistributions in binary form must reproduce the above copyright notice, 12268115Srmacklem * this list of conditions and the following disclaimer in the documentation 13268115Srmacklem * and/or other materials provided with the distribution. 14268115Srmacklem * - Neither the name of Sun Microsystems, Inc. nor the names of its 15268115Srmacklem * contributors may be used to endorse or promote products derived 16268115Srmacklem * from this software without specific prior written permission. 17268115Srmacklem * 18268115Srmacklem * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19268115Srmacklem * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20268115Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21268115Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22268115Srmacklem * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23268115Srmacklem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24268115Srmacklem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25268115Srmacklem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26268115Srmacklem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27268115Srmacklem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28268115Srmacklem * POSSIBILITY OF SUCH DAMAGE. 29268115Srmacklem */ 30268115Srmacklem 31268115Srmacklem#if defined(LIBC_SCCS) && !defined(lint) 32268115Srmacklemstatic char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 33268115Srmacklemstatic char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34268115Srmacklemstatic char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 35268115Srmacklem#endif 36268115Srmacklem#include <sys/cdefs.h> 37268115Srmacklem__FBSDID("$FreeBSD$"); 38268115Srmacklem 39268115Srmacklem/* 40268115Srmacklem * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 41268115Srmacklem * 42268115Srmacklem * Copyright (C) 1984, Sun Microsystems, Inc. 43268115Srmacklem * 44268115Srmacklem * TCP based RPC supports 'batched calls'. 45268115Srmacklem * A sequence of calls may be batched-up in a send buffer. The rpc call 46268115Srmacklem * return immediately to the client even though the call was not necessarily 47268115Srmacklem * sent. The batching occurs if the results' xdr routine is NULL (0) AND 48268115Srmacklem * the rpc timeout value is zero (see clnt.h, rpc). 49268115Srmacklem * 50268115Srmacklem * Clients should NOT casually batch calls that in fact return results; that is, 51268115Srmacklem * the server side should be aware that a call is batched and not produce any 52268115Srmacklem * return message. Batched calls that produce many result messages can 53268115Srmacklem * deadlock (netlock) the client and the server.... 54268115Srmacklem * 55268115Srmacklem * Now go hang yourself. 56268115Srmacklem */ 57268115Srmacklem 58268115Srmacklem/* 59268115Srmacklem * This code handles the special case of a NFSv4.n backchannel for 60268115Srmacklem * callback RPCs. It is similar to clnt_vc.c, but uses the TCP 61268115Srmacklem * connection provided by the client to the server. 62268115Srmacklem */ 63268115Srmacklem 64268115Srmacklem#include <sys/param.h> 65268115Srmacklem#include <sys/systm.h> 66268115Srmacklem#include <sys/lock.h> 67268115Srmacklem#include <sys/malloc.h> 68268115Srmacklem#include <sys/mbuf.h> 69268115Srmacklem#include <sys/mutex.h> 70268115Srmacklem#include <sys/pcpu.h> 71268115Srmacklem#include <sys/proc.h> 72268115Srmacklem#include <sys/protosw.h> 73268115Srmacklem#include <sys/socket.h> 74268115Srmacklem#include <sys/socketvar.h> 75268115Srmacklem#include <sys/sx.h> 76268115Srmacklem#include <sys/syslog.h> 77268115Srmacklem#include <sys/time.h> 78268115Srmacklem#include <sys/uio.h> 79268115Srmacklem 80268115Srmacklem#include <net/vnet.h> 81268115Srmacklem 82268115Srmacklem#include <netinet/tcp.h> 83268115Srmacklem 84268115Srmacklem#include <rpc/rpc.h> 85268115Srmacklem#include <rpc/rpc_com.h> 86268115Srmacklem#include <rpc/krpc.h> 87268115Srmacklem 88268115Srmacklemstruct cmessage { 89268115Srmacklem struct cmsghdr cmsg; 90268115Srmacklem struct cmsgcred cmcred; 91268115Srmacklem}; 92268115Srmacklem 93268115Srmacklemstatic void clnt_bck_geterr(CLIENT *, struct rpc_err *); 94268115Srmacklemstatic bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *); 95268115Srmacklemstatic void clnt_bck_abort(CLIENT *); 96268115Srmacklemstatic bool_t clnt_bck_control(CLIENT *, u_int, void *); 97268115Srmacklemstatic void clnt_bck_close(CLIENT *); 98268115Srmacklemstatic void clnt_bck_destroy(CLIENT *); 99268115Srmacklem 100268115Srmacklemstatic struct clnt_ops clnt_bck_ops = { 101268115Srmacklem .cl_abort = clnt_bck_abort, 102268115Srmacklem .cl_geterr = clnt_bck_geterr, 103268115Srmacklem .cl_freeres = clnt_bck_freeres, 104268115Srmacklem .cl_close = clnt_bck_close, 105268115Srmacklem .cl_destroy = clnt_bck_destroy, 106268115Srmacklem .cl_control = clnt_bck_control 107268115Srmacklem}; 108268115Srmacklem 109268115Srmacklem/* 110268115Srmacklem * Create a client handle for a connection. 111268115Srmacklem * Default options are set, which the user can change using clnt_control()'s. 112268115Srmacklem * This code handles the special case of an NFSv4.1 session backchannel 113268115Srmacklem * call, which is sent on a TCP connection created against the server 114268115Srmacklem * by a client. 115268115Srmacklem */ 116268115Srmacklemvoid * 117268115Srmacklemclnt_bck_create( 118268115Srmacklem struct socket *so, /* Server transport socket. */ 119268115Srmacklem const rpcprog_t prog, /* program number */ 120268115Srmacklem const rpcvers_t vers) /* version number */ 121268115Srmacklem{ 122268115Srmacklem CLIENT *cl; /* client handle */ 123268115Srmacklem struct ct_data *ct = NULL; /* client handle */ 124268115Srmacklem struct timeval now; 125268115Srmacklem struct rpc_msg call_msg; 126268115Srmacklem static uint32_t disrupt; 127268115Srmacklem XDR xdrs; 128268115Srmacklem 129268115Srmacklem if (disrupt == 0) 130268115Srmacklem disrupt = (uint32_t)(long)so; 131268115Srmacklem 132268115Srmacklem cl = (CLIENT *)mem_alloc(sizeof (*cl)); 133268115Srmacklem ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 134268115Srmacklem 135268115Srmacklem mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF); 136268115Srmacklem ct->ct_threads = 0; 137268115Srmacklem ct->ct_closing = FALSE; 138268115Srmacklem ct->ct_closed = FALSE; 139268115Srmacklem ct->ct_upcallrefs = 0; 140268115Srmacklem ct->ct_closeit = FALSE; 141268115Srmacklem 142268115Srmacklem /* 143268115Srmacklem * Set up private data struct 144268115Srmacklem */ 145268115Srmacklem ct->ct_wait.tv_sec = -1; 146268115Srmacklem ct->ct_wait.tv_usec = -1; 147268115Srmacklem 148268115Srmacklem /* 149268115Srmacklem * Initialize call message 150268115Srmacklem */ 151268115Srmacklem getmicrotime(&now); 152268115Srmacklem ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now); 153268115Srmacklem call_msg.rm_xid = ct->ct_xid; 154268115Srmacklem call_msg.rm_direction = CALL; 155268115Srmacklem call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 156268115Srmacklem call_msg.rm_call.cb_prog = (uint32_t)prog; 157268115Srmacklem call_msg.rm_call.cb_vers = (uint32_t)vers; 158268115Srmacklem 159268115Srmacklem /* 160268115Srmacklem * pre-serialize the static part of the call msg and stash it away 161268115Srmacklem */ 162268115Srmacklem xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE, 163268115Srmacklem XDR_ENCODE); 164268115Srmacklem if (!xdr_callhdr(&xdrs, &call_msg)) 165268115Srmacklem goto err; 166268115Srmacklem ct->ct_mpos = XDR_GETPOS(&xdrs); 167268115Srmacklem XDR_DESTROY(&xdrs); 168268115Srmacklem ct->ct_waitchan = "rpcbck"; 169268115Srmacklem ct->ct_waitflag = 0; 170268115Srmacklem cl->cl_refs = 1; 171268115Srmacklem cl->cl_ops = &clnt_bck_ops; 172268115Srmacklem cl->cl_private = ct; 173268115Srmacklem cl->cl_auth = authnone_create(); 174268115Srmacklem TAILQ_INIT(&ct->ct_pending); 175268115Srmacklem return (cl); 176268115Srmacklem 177268115Srmacklemerr: 178268115Srmacklem if (cl) { 179268115Srmacklem if (ct) { 180268115Srmacklem mtx_destroy(&ct->ct_lock); 181268115Srmacklem mem_free(ct, sizeof (struct ct_data)); 182268115Srmacklem } 183268115Srmacklem if (cl) 184268115Srmacklem mem_free(cl, sizeof (CLIENT)); 185268115Srmacklem } 186268115Srmacklem return (NULL); 187268115Srmacklem} 188268115Srmacklem 189268115Srmacklemenum clnt_stat 190268115Srmacklemclnt_bck_call( 191268115Srmacklem CLIENT *cl, /* client handle */ 192268115Srmacklem struct rpc_callextra *ext, /* call metadata */ 193268115Srmacklem rpcproc_t proc, /* procedure number */ 194268115Srmacklem struct mbuf *args, /* pointer to args */ 195268115Srmacklem struct mbuf **resultsp, /* pointer to results */ 196268115Srmacklem struct timeval utimeout, 197268115Srmacklem SVCXPRT *xprt) 198268115Srmacklem{ 199268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 200268115Srmacklem AUTH *auth; 201268115Srmacklem struct rpc_err *errp; 202268115Srmacklem enum clnt_stat stat; 203268115Srmacklem XDR xdrs; 204268115Srmacklem struct rpc_msg reply_msg; 205268115Srmacklem bool_t ok; 206268115Srmacklem int nrefreshes = 2; /* number of times to refresh cred */ 207268115Srmacklem struct timeval timeout; 208268115Srmacklem uint32_t xid; 209268115Srmacklem struct mbuf *mreq = NULL, *results; 210268115Srmacklem struct ct_request *cr; 211268115Srmacklem int error; 212268115Srmacklem 213268115Srmacklem cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK); 214268115Srmacklem 215268115Srmacklem mtx_lock(&ct->ct_lock); 216268115Srmacklem 217268115Srmacklem if (ct->ct_closing || ct->ct_closed) { 218268115Srmacklem mtx_unlock(&ct->ct_lock); 219268115Srmacklem free(cr, M_RPC); 220268115Srmacklem return (RPC_CANTSEND); 221268115Srmacklem } 222268115Srmacklem ct->ct_threads++; 223268115Srmacklem 224268115Srmacklem if (ext) { 225268115Srmacklem auth = ext->rc_auth; 226268115Srmacklem errp = &ext->rc_err; 227268115Srmacklem } else { 228268115Srmacklem auth = cl->cl_auth; 229268115Srmacklem errp = &ct->ct_error; 230268115Srmacklem } 231268115Srmacklem 232268115Srmacklem cr->cr_mrep = NULL; 233268115Srmacklem cr->cr_error = 0; 234268115Srmacklem 235268115Srmacklem if (ct->ct_wait.tv_usec == -1) 236268115Srmacklem timeout = utimeout; /* use supplied timeout */ 237268115Srmacklem else 238268115Srmacklem timeout = ct->ct_wait; /* use default timeout */ 239268115Srmacklem 240268115Srmacklemcall_again: 241268115Srmacklem mtx_assert(&ct->ct_lock, MA_OWNED); 242268115Srmacklem 243268115Srmacklem ct->ct_xid++; 244268115Srmacklem xid = ct->ct_xid; 245268115Srmacklem 246268115Srmacklem mtx_unlock(&ct->ct_lock); 247268115Srmacklem 248268115Srmacklem /* 249268115Srmacklem * Leave space to pre-pend the record mark. 250268115Srmacklem */ 251268115Srmacklem mreq = m_gethdr(M_WAITOK, MT_DATA); 252268115Srmacklem mreq->m_data += sizeof(uint32_t); 253268115Srmacklem KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN, 254268115Srmacklem ("RPC header too big")); 255268115Srmacklem bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos); 256268115Srmacklem mreq->m_len = ct->ct_mpos; 257268115Srmacklem 258268115Srmacklem /* 259268115Srmacklem * The XID is the first thing in the request. 260268115Srmacklem */ 261268115Srmacklem *mtod(mreq, uint32_t *) = htonl(xid); 262268115Srmacklem 263268115Srmacklem xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 264268115Srmacklem 265268115Srmacklem errp->re_status = stat = RPC_SUCCESS; 266268115Srmacklem 267268115Srmacklem if ((!XDR_PUTINT32(&xdrs, &proc)) || 268268115Srmacklem (!AUTH_MARSHALL(auth, xid, &xdrs, 269268115Srmacklem m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 270268115Srmacklem errp->re_status = stat = RPC_CANTENCODEARGS; 271268115Srmacklem mtx_lock(&ct->ct_lock); 272268115Srmacklem goto out; 273268115Srmacklem } 274268115Srmacklem mreq->m_pkthdr.len = m_length(mreq, NULL); 275268115Srmacklem 276268115Srmacklem /* 277268115Srmacklem * Prepend a record marker containing the packet length. 278268115Srmacklem */ 279268115Srmacklem M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK); 280268115Srmacklem *mtod(mreq, uint32_t *) = 281268115Srmacklem htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t))); 282268115Srmacklem 283268115Srmacklem cr->cr_xid = xid; 284268115Srmacklem mtx_lock(&ct->ct_lock); 285268115Srmacklem /* 286268115Srmacklem * Check to see if the client end has already started to close down 287268115Srmacklem * the connection. The svc code will have set ct_error.re_status 288268115Srmacklem * to RPC_CANTRECV if this is the case. 289268115Srmacklem * If the client starts to close down the connection after this 290268115Srmacklem * point, it will be detected later when cr_error is checked, 291268115Srmacklem * since the request is in the ct_pending queue. 292268115Srmacklem */ 293268115Srmacklem if (ct->ct_error.re_status == RPC_CANTRECV) { 294268115Srmacklem if (errp != &ct->ct_error) { 295268115Srmacklem errp->re_errno = ct->ct_error.re_errno; 296268115Srmacklem errp->re_status = RPC_CANTRECV; 297268115Srmacklem } 298268115Srmacklem stat = RPC_CANTRECV; 299268115Srmacklem goto out; 300268115Srmacklem } 301268115Srmacklem TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link); 302268115Srmacklem mtx_unlock(&ct->ct_lock); 303268115Srmacklem 304268115Srmacklem /* 305268115Srmacklem * sosend consumes mreq. 306268115Srmacklem */ 307268115Srmacklem sx_xlock(&xprt->xp_lock); 308268115Srmacklem error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread); 309268115Srmacklemif (error != 0) printf("sosend=%d\n", error); 310268115Srmacklem mreq = NULL; 311268115Srmacklem if (error == EMSGSIZE) { 312268115Srmacklemprintf("emsgsize\n"); 313268115Srmacklem SOCKBUF_LOCK(&xprt->xp_socket->so_snd); 314268115Srmacklem sbwait(&xprt->xp_socket->so_snd); 315268115Srmacklem SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd); 316268115Srmacklem sx_xunlock(&xprt->xp_lock); 317268115Srmacklem AUTH_VALIDATE(auth, xid, NULL, NULL); 318268115Srmacklem mtx_lock(&ct->ct_lock); 319268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 320268115Srmacklem goto call_again; 321268115Srmacklem } 322268115Srmacklem sx_xunlock(&xprt->xp_lock); 323268115Srmacklem 324268115Srmacklem reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 325268115Srmacklem reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 326268115Srmacklem reply_msg.acpted_rply.ar_verf.oa_length = 0; 327268115Srmacklem reply_msg.acpted_rply.ar_results.where = NULL; 328268115Srmacklem reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 329268115Srmacklem 330268115Srmacklem mtx_lock(&ct->ct_lock); 331268115Srmacklem if (error) { 332268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 333268115Srmacklem errp->re_errno = error; 334268115Srmacklem errp->re_status = stat = RPC_CANTSEND; 335268115Srmacklem goto out; 336268115Srmacklem } 337268115Srmacklem 338268115Srmacklem /* 339268115Srmacklem * Check to see if we got an upcall while waiting for the 340268115Srmacklem * lock. In both these cases, the request has been removed 341268115Srmacklem * from ct->ct_pending. 342268115Srmacklem */ 343268115Srmacklem if (cr->cr_error) { 344268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 345268115Srmacklem errp->re_errno = cr->cr_error; 346268115Srmacklem errp->re_status = stat = RPC_CANTRECV; 347268115Srmacklem goto out; 348268115Srmacklem } 349268115Srmacklem if (cr->cr_mrep) { 350268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 351268115Srmacklem goto got_reply; 352268115Srmacklem } 353268115Srmacklem 354268115Srmacklem /* 355268115Srmacklem * Hack to provide rpc-based message passing 356268115Srmacklem */ 357268115Srmacklem if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 358268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 359268115Srmacklem errp->re_status = stat = RPC_TIMEDOUT; 360268115Srmacklem goto out; 361268115Srmacklem } 362268115Srmacklem 363268115Srmacklem error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan, 364268115Srmacklem tvtohz(&timeout)); 365268115Srmacklem 366268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 367268115Srmacklem 368268115Srmacklem if (error) { 369268115Srmacklem /* 370268115Srmacklem * The sleep returned an error so our request is still 371268115Srmacklem * on the list. Turn the error code into an 372268115Srmacklem * appropriate client status. 373268115Srmacklem */ 374268115Srmacklem errp->re_errno = error; 375268115Srmacklem switch (error) { 376268115Srmacklem case EINTR: 377268115Srmacklem stat = RPC_INTR; 378268115Srmacklem break; 379268115Srmacklem case EWOULDBLOCK: 380268115Srmacklem stat = RPC_TIMEDOUT; 381268115Srmacklem break; 382268115Srmacklem default: 383268115Srmacklem stat = RPC_CANTRECV; 384268115Srmacklem }; 385268115Srmacklem errp->re_status = stat; 386268115Srmacklem goto out; 387268115Srmacklem } else { 388268115Srmacklem /* 389268115Srmacklem * We were woken up by the svc thread. If the 390268115Srmacklem * upcall had a receive error, report that, 391268115Srmacklem * otherwise we have a reply. 392268115Srmacklem */ 393268115Srmacklem if (cr->cr_error) { 394268115Srmacklem errp->re_errno = cr->cr_error; 395268115Srmacklem errp->re_status = stat = RPC_CANTRECV; 396268115Srmacklem goto out; 397268115Srmacklem } 398268115Srmacklem } 399268115Srmacklem 400268115Srmacklemgot_reply: 401268115Srmacklem /* 402268115Srmacklem * Now decode and validate the response. We need to drop the 403268115Srmacklem * lock since xdr_replymsg may end up sleeping in malloc. 404268115Srmacklem */ 405268115Srmacklem mtx_unlock(&ct->ct_lock); 406268115Srmacklem 407268115Srmacklem if (ext && ext->rc_feedback) 408268115Srmacklem ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg); 409268115Srmacklem 410268115Srmacklem xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); 411268115Srmacklem ok = xdr_replymsg(&xdrs, &reply_msg); 412268115Srmacklem cr->cr_mrep = NULL; 413268115Srmacklem 414268115Srmacklem if (ok) { 415268115Srmacklem if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 416268115Srmacklem (reply_msg.acpted_rply.ar_stat == SUCCESS)) 417268115Srmacklem errp->re_status = stat = RPC_SUCCESS; 418268115Srmacklem else 419268115Srmacklem stat = _seterr_reply(&reply_msg, errp); 420268115Srmacklem 421268115Srmacklem if (stat == RPC_SUCCESS) { 422268115Srmacklem results = xdrmbuf_getall(&xdrs); 423268115Srmacklem if (!AUTH_VALIDATE(auth, xid, 424268115Srmacklem &reply_msg.acpted_rply.ar_verf, &results)) { 425268115Srmacklem errp->re_status = stat = RPC_AUTHERROR; 426268115Srmacklem errp->re_why = AUTH_INVALIDRESP; 427268115Srmacklem } else { 428268115Srmacklem KASSERT(results, 429268115Srmacklem ("auth validated but no result")); 430268115Srmacklem *resultsp = results; 431268115Srmacklem } 432268115Srmacklem } /* end successful completion */ 433268115Srmacklem /* 434268115Srmacklem * If unsuccesful AND error is an authentication error 435268115Srmacklem * then refresh credentials and try again, else break 436268115Srmacklem */ 437268115Srmacklem else if (stat == RPC_AUTHERROR) 438268115Srmacklem /* maybe our credentials need to be refreshed ... */ 439268115Srmacklem if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) { 440268115Srmacklem nrefreshes--; 441268115Srmacklem XDR_DESTROY(&xdrs); 442268115Srmacklem mtx_lock(&ct->ct_lock); 443268115Srmacklem goto call_again; 444268115Srmacklem } 445268115Srmacklem /* end of unsuccessful completion */ 446268115Srmacklem /* end of valid reply message */ 447268115Srmacklem } else 448268115Srmacklem errp->re_status = stat = RPC_CANTDECODERES; 449268115Srmacklem XDR_DESTROY(&xdrs); 450268115Srmacklem mtx_lock(&ct->ct_lock); 451268115Srmacklemout: 452268115Srmacklem mtx_assert(&ct->ct_lock, MA_OWNED); 453268115Srmacklem 454268115Srmacklem KASSERT(stat != RPC_SUCCESS || *resultsp, 455268115Srmacklem ("RPC_SUCCESS without reply")); 456268115Srmacklem 457268115Srmacklem if (mreq != NULL) 458268115Srmacklem m_freem(mreq); 459268115Srmacklem if (cr->cr_mrep != NULL) 460268115Srmacklem m_freem(cr->cr_mrep); 461268115Srmacklem 462268115Srmacklem ct->ct_threads--; 463268115Srmacklem if (ct->ct_closing) 464268115Srmacklem wakeup(ct); 465268115Srmacklem 466268115Srmacklem mtx_unlock(&ct->ct_lock); 467268115Srmacklem 468268115Srmacklem if (auth && stat != RPC_SUCCESS) 469268115Srmacklem AUTH_VALIDATE(auth, xid, NULL, NULL); 470268115Srmacklem 471268115Srmacklem free(cr, M_RPC); 472268115Srmacklem 473268115Srmacklem return (stat); 474268115Srmacklem} 475268115Srmacklem 476268115Srmacklemstatic void 477268115Srmacklemclnt_bck_geterr(CLIENT *cl, struct rpc_err *errp) 478268115Srmacklem{ 479268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 480268115Srmacklem 481268115Srmacklem *errp = ct->ct_error; 482268115Srmacklem} 483268115Srmacklem 484268115Srmacklemstatic bool_t 485268115Srmacklemclnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 486268115Srmacklem{ 487268115Srmacklem XDR xdrs; 488268115Srmacklem bool_t dummy; 489268115Srmacklem 490268115Srmacklem xdrs.x_op = XDR_FREE; 491268115Srmacklem dummy = (*xdr_res)(&xdrs, res_ptr); 492268115Srmacklem 493268115Srmacklem return (dummy); 494268115Srmacklem} 495268115Srmacklem 496268115Srmacklem/*ARGSUSED*/ 497268115Srmacklemstatic void 498268115Srmacklemclnt_bck_abort(CLIENT *cl) 499268115Srmacklem{ 500268115Srmacklem} 501268115Srmacklem 502268115Srmacklemstatic bool_t 503268115Srmacklemclnt_bck_control(CLIENT *cl, u_int request, void *info) 504268115Srmacklem{ 505268115Srmacklem 506268115Srmacklem return (TRUE); 507268115Srmacklem} 508268115Srmacklem 509268115Srmacklemstatic void 510268115Srmacklemclnt_bck_close(CLIENT *cl) 511268115Srmacklem{ 512268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 513268115Srmacklem 514268115Srmacklem mtx_lock(&ct->ct_lock); 515268115Srmacklem 516268115Srmacklem if (ct->ct_closed) { 517268115Srmacklem mtx_unlock(&ct->ct_lock); 518268115Srmacklem return; 519268115Srmacklem } 520268115Srmacklem 521268115Srmacklem if (ct->ct_closing) { 522268115Srmacklem while (ct->ct_closing) 523268115Srmacklem msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 524268115Srmacklem KASSERT(ct->ct_closed, ("client should be closed")); 525268115Srmacklem mtx_unlock(&ct->ct_lock); 526268115Srmacklem return; 527268115Srmacklem } 528268115Srmacklem 529268115Srmacklem ct->ct_closing = FALSE; 530268115Srmacklem ct->ct_closed = TRUE; 531268115Srmacklem mtx_unlock(&ct->ct_lock); 532268115Srmacklem wakeup(ct); 533268115Srmacklem} 534268115Srmacklem 535268115Srmacklemstatic void 536268115Srmacklemclnt_bck_destroy(CLIENT *cl) 537268115Srmacklem{ 538268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 539268115Srmacklem 540268115Srmacklem clnt_bck_close(cl); 541268115Srmacklem 542268115Srmacklem mtx_destroy(&ct->ct_lock); 543268115Srmacklem mem_free(ct, sizeof(struct ct_data)); 544268115Srmacklem if (cl->cl_netid && cl->cl_netid[0]) 545268115Srmacklem mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 546268115Srmacklem if (cl->cl_tp && cl->cl_tp[0]) 547268115Srmacklem mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 548268115Srmacklem mem_free(cl, sizeof(CLIENT)); 549268115Srmacklem} 550268115Srmacklem 551268115Srmacklem/* 552268115Srmacklem * This call is done by the svc code when a backchannel RPC reply is 553268115Srmacklem * received. 554268115Srmacklem */ 555268115Srmacklemvoid 556268115Srmacklemclnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid) 557268115Srmacklem{ 558268115Srmacklem struct ct_data *ct = (struct ct_data *)arg; 559268115Srmacklem struct ct_request *cr; 560268115Srmacklem int foundreq; 561268115Srmacklem 562268115Srmacklem mtx_lock(&ct->ct_lock); 563268115Srmacklem ct->ct_upcallrefs++; 564268115Srmacklem /* 565268115Srmacklem * See if we can match this reply to a request. 566268115Srmacklem */ 567268115Srmacklem foundreq = 0; 568268115Srmacklem TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 569268115Srmacklem if (cr->cr_xid == xid) { 570268115Srmacklem /* 571268115Srmacklem * This one matches. We leave the reply mbuf list in 572268115Srmacklem * cr->cr_mrep. Set the XID to zero so that we will 573268115Srmacklem * ignore any duplicated replies. 574268115Srmacklem */ 575268115Srmacklem cr->cr_xid = 0; 576268115Srmacklem cr->cr_mrep = mrep; 577268115Srmacklem cr->cr_error = 0; 578268115Srmacklem foundreq = 1; 579268115Srmacklem wakeup(cr); 580268115Srmacklem break; 581268115Srmacklem } 582268115Srmacklem } 583268115Srmacklem 584268115Srmacklem ct->ct_upcallrefs--; 585268115Srmacklem if (ct->ct_upcallrefs < 0) 586268115Srmacklem panic("rpcvc svccall refcnt"); 587268115Srmacklem if (ct->ct_upcallrefs == 0) 588268115Srmacklem wakeup(&ct->ct_upcallrefs); 589268115Srmacklem mtx_unlock(&ct->ct_lock); 590268115Srmacklem if (foundreq == 0) 591268115Srmacklem m_freem(mrep); 592268115Srmacklem} 593268115Srmacklem 594