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