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