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: 178302451Sngie mtx_destroy(&ct->ct_lock); 179302451Sngie mem_free(ct, sizeof (struct ct_data)); 180302451Sngie mem_free(cl, sizeof (CLIENT)); 181268115Srmacklem return (NULL); 182268115Srmacklem} 183268115Srmacklem 184268115Srmacklemenum clnt_stat 185268115Srmacklemclnt_bck_call( 186268115Srmacklem CLIENT *cl, /* client handle */ 187268115Srmacklem struct rpc_callextra *ext, /* call metadata */ 188268115Srmacklem rpcproc_t proc, /* procedure number */ 189268115Srmacklem struct mbuf *args, /* pointer to args */ 190268115Srmacklem struct mbuf **resultsp, /* pointer to results */ 191268115Srmacklem struct timeval utimeout, 192268115Srmacklem SVCXPRT *xprt) 193268115Srmacklem{ 194268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 195268115Srmacklem AUTH *auth; 196268115Srmacklem struct rpc_err *errp; 197268115Srmacklem enum clnt_stat stat; 198268115Srmacklem XDR xdrs; 199268115Srmacklem struct rpc_msg reply_msg; 200268115Srmacklem bool_t ok; 201268115Srmacklem int nrefreshes = 2; /* number of times to refresh cred */ 202268115Srmacklem struct timeval timeout; 203268115Srmacklem uint32_t xid; 204268115Srmacklem struct mbuf *mreq = NULL, *results; 205268115Srmacklem struct ct_request *cr; 206268115Srmacklem int error; 207268115Srmacklem 208268115Srmacklem cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK); 209268115Srmacklem 210268115Srmacklem mtx_lock(&ct->ct_lock); 211268115Srmacklem 212268115Srmacklem if (ct->ct_closing || ct->ct_closed) { 213268115Srmacklem mtx_unlock(&ct->ct_lock); 214268115Srmacklem free(cr, M_RPC); 215268115Srmacklem return (RPC_CANTSEND); 216268115Srmacklem } 217268115Srmacklem ct->ct_threads++; 218268115Srmacklem 219268115Srmacklem if (ext) { 220268115Srmacklem auth = ext->rc_auth; 221268115Srmacklem errp = &ext->rc_err; 222268115Srmacklem } else { 223268115Srmacklem auth = cl->cl_auth; 224268115Srmacklem errp = &ct->ct_error; 225268115Srmacklem } 226268115Srmacklem 227268115Srmacklem cr->cr_mrep = NULL; 228268115Srmacklem cr->cr_error = 0; 229268115Srmacklem 230268115Srmacklem if (ct->ct_wait.tv_usec == -1) 231268115Srmacklem timeout = utimeout; /* use supplied timeout */ 232268115Srmacklem else 233268115Srmacklem timeout = ct->ct_wait; /* use default timeout */ 234268115Srmacklem 235268115Srmacklemcall_again: 236268115Srmacklem mtx_assert(&ct->ct_lock, MA_OWNED); 237268115Srmacklem 238268115Srmacklem ct->ct_xid++; 239268115Srmacklem xid = ct->ct_xid; 240268115Srmacklem 241268115Srmacklem mtx_unlock(&ct->ct_lock); 242268115Srmacklem 243268115Srmacklem /* 244268115Srmacklem * Leave space to pre-pend the record mark. 245268115Srmacklem */ 246268115Srmacklem mreq = m_gethdr(M_WAITOK, MT_DATA); 247268115Srmacklem mreq->m_data += sizeof(uint32_t); 248268115Srmacklem KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN, 249268115Srmacklem ("RPC header too big")); 250268115Srmacklem bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos); 251268115Srmacklem mreq->m_len = ct->ct_mpos; 252268115Srmacklem 253268115Srmacklem /* 254268115Srmacklem * The XID is the first thing in the request. 255268115Srmacklem */ 256268115Srmacklem *mtod(mreq, uint32_t *) = htonl(xid); 257268115Srmacklem 258268115Srmacklem xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 259268115Srmacklem 260268115Srmacklem errp->re_status = stat = RPC_SUCCESS; 261268115Srmacklem 262268115Srmacklem if ((!XDR_PUTINT32(&xdrs, &proc)) || 263268115Srmacklem (!AUTH_MARSHALL(auth, xid, &xdrs, 264268115Srmacklem m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 265268115Srmacklem errp->re_status = stat = RPC_CANTENCODEARGS; 266268115Srmacklem mtx_lock(&ct->ct_lock); 267268115Srmacklem goto out; 268268115Srmacklem } 269268115Srmacklem mreq->m_pkthdr.len = m_length(mreq, NULL); 270268115Srmacklem 271268115Srmacklem /* 272268115Srmacklem * Prepend a record marker containing the packet length. 273268115Srmacklem */ 274268115Srmacklem M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK); 275268115Srmacklem *mtod(mreq, uint32_t *) = 276268115Srmacklem htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t))); 277268115Srmacklem 278268115Srmacklem cr->cr_xid = xid; 279268115Srmacklem mtx_lock(&ct->ct_lock); 280268115Srmacklem /* 281268115Srmacklem * Check to see if the client end has already started to close down 282268115Srmacklem * the connection. The svc code will have set ct_error.re_status 283268115Srmacklem * to RPC_CANTRECV if this is the case. 284268115Srmacklem * If the client starts to close down the connection after this 285268115Srmacklem * point, it will be detected later when cr_error is checked, 286268115Srmacklem * since the request is in the ct_pending queue. 287268115Srmacklem */ 288268115Srmacklem if (ct->ct_error.re_status == RPC_CANTRECV) { 289268115Srmacklem if (errp != &ct->ct_error) { 290268115Srmacklem errp->re_errno = ct->ct_error.re_errno; 291268115Srmacklem errp->re_status = RPC_CANTRECV; 292268115Srmacklem } 293268115Srmacklem stat = RPC_CANTRECV; 294268115Srmacklem goto out; 295268115Srmacklem } 296268115Srmacklem TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link); 297268115Srmacklem mtx_unlock(&ct->ct_lock); 298268115Srmacklem 299268115Srmacklem /* 300268115Srmacklem * sosend consumes mreq. 301268115Srmacklem */ 302268115Srmacklem sx_xlock(&xprt->xp_lock); 303268115Srmacklem error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread); 304268115Srmacklemif (error != 0) printf("sosend=%d\n", error); 305268115Srmacklem mreq = NULL; 306268115Srmacklem if (error == EMSGSIZE) { 307268115Srmacklemprintf("emsgsize\n"); 308268115Srmacklem SOCKBUF_LOCK(&xprt->xp_socket->so_snd); 309268115Srmacklem sbwait(&xprt->xp_socket->so_snd); 310268115Srmacklem SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd); 311268115Srmacklem sx_xunlock(&xprt->xp_lock); 312268115Srmacklem AUTH_VALIDATE(auth, xid, NULL, NULL); 313268115Srmacklem mtx_lock(&ct->ct_lock); 314268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 315268115Srmacklem goto call_again; 316268115Srmacklem } 317268115Srmacklem sx_xunlock(&xprt->xp_lock); 318268115Srmacklem 319268115Srmacklem reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 320268115Srmacklem reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 321268115Srmacklem reply_msg.acpted_rply.ar_verf.oa_length = 0; 322268115Srmacklem reply_msg.acpted_rply.ar_results.where = NULL; 323268115Srmacklem reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 324268115Srmacklem 325268115Srmacklem mtx_lock(&ct->ct_lock); 326268115Srmacklem if (error) { 327268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 328268115Srmacklem errp->re_errno = error; 329268115Srmacklem errp->re_status = stat = RPC_CANTSEND; 330268115Srmacklem goto out; 331268115Srmacklem } 332268115Srmacklem 333268115Srmacklem /* 334268115Srmacklem * Check to see if we got an upcall while waiting for the 335268115Srmacklem * lock. In both these cases, the request has been removed 336268115Srmacklem * from ct->ct_pending. 337268115Srmacklem */ 338268115Srmacklem if (cr->cr_error) { 339268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 340268115Srmacklem errp->re_errno = cr->cr_error; 341268115Srmacklem errp->re_status = stat = RPC_CANTRECV; 342268115Srmacklem goto out; 343268115Srmacklem } 344268115Srmacklem if (cr->cr_mrep) { 345268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 346268115Srmacklem goto got_reply; 347268115Srmacklem } 348268115Srmacklem 349268115Srmacklem /* 350268115Srmacklem * Hack to provide rpc-based message passing 351268115Srmacklem */ 352268115Srmacklem if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 353268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 354268115Srmacklem errp->re_status = stat = RPC_TIMEDOUT; 355268115Srmacklem goto out; 356268115Srmacklem } 357268115Srmacklem 358268115Srmacklem error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan, 359268115Srmacklem tvtohz(&timeout)); 360268115Srmacklem 361268115Srmacklem TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 362268115Srmacklem 363268115Srmacklem if (error) { 364268115Srmacklem /* 365268115Srmacklem * The sleep returned an error so our request is still 366268115Srmacklem * on the list. Turn the error code into an 367268115Srmacklem * appropriate client status. 368268115Srmacklem */ 369268115Srmacklem errp->re_errno = error; 370268115Srmacklem switch (error) { 371268115Srmacklem case EINTR: 372268115Srmacklem stat = RPC_INTR; 373268115Srmacklem break; 374268115Srmacklem case EWOULDBLOCK: 375268115Srmacklem stat = RPC_TIMEDOUT; 376268115Srmacklem break; 377268115Srmacklem default: 378268115Srmacklem stat = RPC_CANTRECV; 379268115Srmacklem }; 380268115Srmacklem errp->re_status = stat; 381268115Srmacklem goto out; 382268115Srmacklem } else { 383268115Srmacklem /* 384268115Srmacklem * We were woken up by the svc thread. If the 385268115Srmacklem * upcall had a receive error, report that, 386268115Srmacklem * otherwise we have a reply. 387268115Srmacklem */ 388268115Srmacklem if (cr->cr_error) { 389268115Srmacklem errp->re_errno = cr->cr_error; 390268115Srmacklem errp->re_status = stat = RPC_CANTRECV; 391268115Srmacklem goto out; 392268115Srmacklem } 393268115Srmacklem } 394268115Srmacklem 395268115Srmacklemgot_reply: 396268115Srmacklem /* 397268115Srmacklem * Now decode and validate the response. We need to drop the 398268115Srmacklem * lock since xdr_replymsg may end up sleeping in malloc. 399268115Srmacklem */ 400268115Srmacklem mtx_unlock(&ct->ct_lock); 401268115Srmacklem 402268115Srmacklem if (ext && ext->rc_feedback) 403268115Srmacklem ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg); 404268115Srmacklem 405268115Srmacklem xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); 406268115Srmacklem ok = xdr_replymsg(&xdrs, &reply_msg); 407268115Srmacklem cr->cr_mrep = NULL; 408268115Srmacklem 409268115Srmacklem if (ok) { 410268115Srmacklem if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 411268115Srmacklem (reply_msg.acpted_rply.ar_stat == SUCCESS)) 412268115Srmacklem errp->re_status = stat = RPC_SUCCESS; 413268115Srmacklem else 414268115Srmacklem stat = _seterr_reply(&reply_msg, errp); 415268115Srmacklem 416268115Srmacklem if (stat == RPC_SUCCESS) { 417268115Srmacklem results = xdrmbuf_getall(&xdrs); 418268115Srmacklem if (!AUTH_VALIDATE(auth, xid, 419268115Srmacklem &reply_msg.acpted_rply.ar_verf, &results)) { 420268115Srmacklem errp->re_status = stat = RPC_AUTHERROR; 421268115Srmacklem errp->re_why = AUTH_INVALIDRESP; 422268115Srmacklem } else { 423268115Srmacklem KASSERT(results, 424268115Srmacklem ("auth validated but no result")); 425268115Srmacklem *resultsp = results; 426268115Srmacklem } 427268115Srmacklem } /* end successful completion */ 428268115Srmacklem /* 429268115Srmacklem * If unsuccesful AND error is an authentication error 430268115Srmacklem * then refresh credentials and try again, else break 431268115Srmacklem */ 432268115Srmacklem else if (stat == RPC_AUTHERROR) 433268115Srmacklem /* maybe our credentials need to be refreshed ... */ 434268115Srmacklem if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) { 435268115Srmacklem nrefreshes--; 436268115Srmacklem XDR_DESTROY(&xdrs); 437268115Srmacklem mtx_lock(&ct->ct_lock); 438268115Srmacklem goto call_again; 439268115Srmacklem } 440268115Srmacklem /* end of unsuccessful completion */ 441268115Srmacklem /* end of valid reply message */ 442268115Srmacklem } else 443268115Srmacklem errp->re_status = stat = RPC_CANTDECODERES; 444268115Srmacklem XDR_DESTROY(&xdrs); 445268115Srmacklem mtx_lock(&ct->ct_lock); 446268115Srmacklemout: 447268115Srmacklem mtx_assert(&ct->ct_lock, MA_OWNED); 448268115Srmacklem 449268115Srmacklem KASSERT(stat != RPC_SUCCESS || *resultsp, 450268115Srmacklem ("RPC_SUCCESS without reply")); 451268115Srmacklem 452268115Srmacklem if (mreq != NULL) 453268115Srmacklem m_freem(mreq); 454268115Srmacklem if (cr->cr_mrep != NULL) 455268115Srmacklem m_freem(cr->cr_mrep); 456268115Srmacklem 457268115Srmacklem ct->ct_threads--; 458268115Srmacklem if (ct->ct_closing) 459268115Srmacklem wakeup(ct); 460268115Srmacklem 461268115Srmacklem mtx_unlock(&ct->ct_lock); 462268115Srmacklem 463268115Srmacklem if (auth && stat != RPC_SUCCESS) 464268115Srmacklem AUTH_VALIDATE(auth, xid, NULL, NULL); 465268115Srmacklem 466268115Srmacklem free(cr, M_RPC); 467268115Srmacklem 468268115Srmacklem return (stat); 469268115Srmacklem} 470268115Srmacklem 471268115Srmacklemstatic void 472268115Srmacklemclnt_bck_geterr(CLIENT *cl, struct rpc_err *errp) 473268115Srmacklem{ 474268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 475268115Srmacklem 476268115Srmacklem *errp = ct->ct_error; 477268115Srmacklem} 478268115Srmacklem 479268115Srmacklemstatic bool_t 480268115Srmacklemclnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 481268115Srmacklem{ 482268115Srmacklem XDR xdrs; 483268115Srmacklem bool_t dummy; 484268115Srmacklem 485268115Srmacklem xdrs.x_op = XDR_FREE; 486268115Srmacklem dummy = (*xdr_res)(&xdrs, res_ptr); 487268115Srmacklem 488268115Srmacklem return (dummy); 489268115Srmacklem} 490268115Srmacklem 491268115Srmacklem/*ARGSUSED*/ 492268115Srmacklemstatic void 493268115Srmacklemclnt_bck_abort(CLIENT *cl) 494268115Srmacklem{ 495268115Srmacklem} 496268115Srmacklem 497268115Srmacklemstatic bool_t 498268115Srmacklemclnt_bck_control(CLIENT *cl, u_int request, void *info) 499268115Srmacklem{ 500268115Srmacklem 501268115Srmacklem return (TRUE); 502268115Srmacklem} 503268115Srmacklem 504268115Srmacklemstatic void 505268115Srmacklemclnt_bck_close(CLIENT *cl) 506268115Srmacklem{ 507268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 508268115Srmacklem 509268115Srmacklem mtx_lock(&ct->ct_lock); 510268115Srmacklem 511268115Srmacklem if (ct->ct_closed) { 512268115Srmacklem mtx_unlock(&ct->ct_lock); 513268115Srmacklem return; 514268115Srmacklem } 515268115Srmacklem 516268115Srmacklem if (ct->ct_closing) { 517268115Srmacklem while (ct->ct_closing) 518268115Srmacklem msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 519268115Srmacklem KASSERT(ct->ct_closed, ("client should be closed")); 520268115Srmacklem mtx_unlock(&ct->ct_lock); 521268115Srmacklem return; 522268115Srmacklem } 523268115Srmacklem 524268115Srmacklem ct->ct_closing = FALSE; 525268115Srmacklem ct->ct_closed = TRUE; 526268115Srmacklem mtx_unlock(&ct->ct_lock); 527268115Srmacklem wakeup(ct); 528268115Srmacklem} 529268115Srmacklem 530268115Srmacklemstatic void 531268115Srmacklemclnt_bck_destroy(CLIENT *cl) 532268115Srmacklem{ 533268115Srmacklem struct ct_data *ct = (struct ct_data *) cl->cl_private; 534268115Srmacklem 535268115Srmacklem clnt_bck_close(cl); 536268115Srmacklem 537268115Srmacklem mtx_destroy(&ct->ct_lock); 538268115Srmacklem mem_free(ct, sizeof(struct ct_data)); 539268115Srmacklem if (cl->cl_netid && cl->cl_netid[0]) 540268115Srmacklem mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 541268115Srmacklem if (cl->cl_tp && cl->cl_tp[0]) 542268115Srmacklem mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 543268115Srmacklem mem_free(cl, sizeof(CLIENT)); 544268115Srmacklem} 545268115Srmacklem 546268115Srmacklem/* 547268115Srmacklem * This call is done by the svc code when a backchannel RPC reply is 548268115Srmacklem * received. 549268115Srmacklem */ 550268115Srmacklemvoid 551268115Srmacklemclnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid) 552268115Srmacklem{ 553268115Srmacklem struct ct_data *ct = (struct ct_data *)arg; 554268115Srmacklem struct ct_request *cr; 555268115Srmacklem int foundreq; 556268115Srmacklem 557268115Srmacklem mtx_lock(&ct->ct_lock); 558268115Srmacklem ct->ct_upcallrefs++; 559268115Srmacklem /* 560268115Srmacklem * See if we can match this reply to a request. 561268115Srmacklem */ 562268115Srmacklem foundreq = 0; 563268115Srmacklem TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 564268115Srmacklem if (cr->cr_xid == xid) { 565268115Srmacklem /* 566268115Srmacklem * This one matches. We leave the reply mbuf list in 567268115Srmacklem * cr->cr_mrep. Set the XID to zero so that we will 568268115Srmacklem * ignore any duplicated replies. 569268115Srmacklem */ 570268115Srmacklem cr->cr_xid = 0; 571268115Srmacklem cr->cr_mrep = mrep; 572268115Srmacklem cr->cr_error = 0; 573268115Srmacklem foundreq = 1; 574268115Srmacklem wakeup(cr); 575268115Srmacklem break; 576268115Srmacklem } 577268115Srmacklem } 578268115Srmacklem 579268115Srmacklem ct->ct_upcallrefs--; 580268115Srmacklem if (ct->ct_upcallrefs < 0) 581268115Srmacklem panic("rpcvc svccall refcnt"); 582268115Srmacklem if (ct->ct_upcallrefs == 0) 583268115Srmacklem wakeup(&ct->ct_upcallrefs); 584268115Srmacklem mtx_unlock(&ct->ct_lock); 585268115Srmacklem if (foundreq == 0) 586268115Srmacklem m_freem(mrep); 587268115Srmacklem} 588268115Srmacklem 589