1177633Sdfr/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2177633Sdfr 3261057Smav/*- 4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261057Smav * All rights reserved. 6261057Smav * 7261057Smav * Redistribution and use in source and binary forms, with or without 8261057Smav * modification, are permitted provided that the following conditions are met: 9261057Smav * - Redistributions of source code must retain the above copyright notice, 10261057Smav * this list of conditions and the following disclaimer. 11261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261057Smav * this list of conditions and the following disclaimer in the documentation 13261057Smav * and/or other materials provided with the distribution. 14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261057Smav * contributors may be used to endorse or promote products derived 16261057Smav * from this software without specific prior written permission. 17177633Sdfr * 18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261057Smav * POSSIBILITY OF SUCH DAMAGE. 29177633Sdfr */ 30177633Sdfr 31177633Sdfr#if defined(LIBC_SCCS) && !defined(lint) 32177633Sdfrstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 33177633Sdfrstatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34177633Sdfr#endif 35177633Sdfr#include <sys/cdefs.h> 36177633Sdfr__FBSDID("$FreeBSD$"); 37177633Sdfr 38177633Sdfr/* 39177633Sdfr * svc_vc.c, Server side for Connection Oriented based RPC. 40177633Sdfr * 41177633Sdfr * Actually implements two flavors of transporter - 42177633Sdfr * a tcp rendezvouser (a listner and connection establisher) 43177633Sdfr * and a record/tcp stream. 44177633Sdfr */ 45177633Sdfr 46177633Sdfr#include <sys/param.h> 47261082Smav#include <sys/limits.h> 48177633Sdfr#include <sys/lock.h> 49177633Sdfr#include <sys/kernel.h> 50177633Sdfr#include <sys/malloc.h> 51177633Sdfr#include <sys/mbuf.h> 52177633Sdfr#include <sys/mutex.h> 53193509Srwatson#include <sys/proc.h> 54177633Sdfr#include <sys/protosw.h> 55177633Sdfr#include <sys/queue.h> 56177633Sdfr#include <sys/socket.h> 57177633Sdfr#include <sys/socketvar.h> 58184588Sdfr#include <sys/sx.h> 59177633Sdfr#include <sys/systm.h> 60177633Sdfr#include <sys/uio.h> 61196503Szec 62196503Szec#include <net/vnet.h> 63196503Szec 64177633Sdfr#include <netinet/tcp.h> 65177633Sdfr 66177633Sdfr#include <rpc/rpc.h> 67177633Sdfr 68261058Smav#include <rpc/krpc.h> 69177685Sdfr#include <rpc/rpc_com.h> 70177633Sdfr 71193509Srwatson#include <security/mac/mac_framework.h> 72193509Srwatson 73184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 74184588Sdfr struct sockaddr **, struct mbuf **); 75177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 76177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *); 77177633Sdfrstatic bool_t svc_vc_null(void); 78177633Sdfrstatic void svc_vc_destroy(SVCXPRT *); 79177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 80261067Smavstatic bool_t svc_vc_ack(SVCXPRT *, uint32_t *); 81184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *, 82184588Sdfr struct sockaddr **, struct mbuf **); 83184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *, 84261067Smav struct sockaddr *, struct mbuf *, uint32_t *seq); 85177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 86177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 87177633Sdfr void *in); 88261058Smavstatic void svc_vc_backchannel_destroy(SVCXPRT *); 89261058Smavstatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *); 90261058Smavstatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *, 91261058Smav struct sockaddr **, struct mbuf **); 92261058Smavstatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *, 93261067Smav struct sockaddr *, struct mbuf *, uint32_t *); 94261058Smavstatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, 95261058Smav void *in); 96177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so, 97177633Sdfr struct sockaddr *raddr); 98177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop); 99193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag); 100177633Sdfr 101177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = { 102177633Sdfr .xp_recv = svc_vc_rendezvous_recv, 103177633Sdfr .xp_stat = svc_vc_rendezvous_stat, 104184588Sdfr .xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *, 105261067Smav struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null, 106177633Sdfr .xp_destroy = svc_vc_rendezvous_destroy, 107177633Sdfr .xp_control = svc_vc_rendezvous_control 108177633Sdfr}; 109177633Sdfr 110177633Sdfrstatic struct xp_ops svc_vc_ops = { 111177633Sdfr .xp_recv = svc_vc_recv, 112177633Sdfr .xp_stat = svc_vc_stat, 113261067Smav .xp_ack = svc_vc_ack, 114177633Sdfr .xp_reply = svc_vc_reply, 115177633Sdfr .xp_destroy = svc_vc_destroy, 116177633Sdfr .xp_control = svc_vc_control 117177633Sdfr}; 118177633Sdfr 119261058Smavstatic struct xp_ops svc_vc_backchannel_ops = { 120261058Smav .xp_recv = svc_vc_backchannel_recv, 121261058Smav .xp_stat = svc_vc_backchannel_stat, 122261058Smav .xp_reply = svc_vc_backchannel_reply, 123261058Smav .xp_destroy = svc_vc_backchannel_destroy, 124261058Smav .xp_control = svc_vc_backchannel_control 125177633Sdfr}; 126177633Sdfr 127177633Sdfr/* 128177633Sdfr * Usage: 129177633Sdfr * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 130177633Sdfr * 131177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter. 132177633Sdfr * Once *xprt is initialized, it is registered as a transporter 133177633Sdfr * see (svc.h, xprt_register). This routine returns 134177633Sdfr * a NULL if a problem occurred. 135177633Sdfr * 136177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but 137177633Sdfr * not yet connected socket. 138177633Sdfr * 139177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify 140177633Sdfr * how big the send and receive buffers are via the second and third parms; 141177633Sdfr * 0 => use the system default. 142177633Sdfr */ 143177633SdfrSVCXPRT * 144177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 145177633Sdfr size_t recvsize) 146177633Sdfr{ 147177633Sdfr SVCXPRT *xprt; 148177633Sdfr struct sockaddr* sa; 149177633Sdfr int error; 150177633Sdfr 151251698Sjhb SOCK_LOCK(so); 152251698Sjhb if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) { 153251698Sjhb SOCK_UNLOCK(so); 154180025Sdfr error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 155180025Sdfr if (error) 156180025Sdfr return (NULL); 157180025Sdfr xprt = svc_vc_create_conn(pool, so, sa); 158180025Sdfr free(sa, M_SONAME); 159180025Sdfr return (xprt); 160180025Sdfr } 161251698Sjhb SOCK_UNLOCK(so); 162180025Sdfr 163184588Sdfr xprt = svc_xprt_alloc(); 164184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 165177633Sdfr xprt->xp_pool = pool; 166177633Sdfr xprt->xp_socket = so; 167177633Sdfr xprt->xp_p1 = NULL; 168177633Sdfr xprt->xp_p2 = NULL; 169177633Sdfr xprt->xp_ops = &svc_vc_rendezvous_ops; 170177633Sdfr 171177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 172196503Szec if (error) { 173177633Sdfr goto cleanup_svc_vc_create; 174196503Szec } 175177633Sdfr 176184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 177177633Sdfr free(sa, M_SONAME); 178177633Sdfr 179177633Sdfr xprt_register(xprt); 180177633Sdfr 181177633Sdfr solisten(so, SOMAXCONN, curthread); 182177633Sdfr 183177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 184193436Srmacklem xprt->xp_upcallset = 1; 185193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 186177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 187177633Sdfr 188177633Sdfr return (xprt); 189177633Sdfrcleanup_svc_vc_create: 190261067Smav if (xprt) { 191261067Smav sx_destroy(&xprt->xp_lock); 192184588Sdfr svc_xprt_free(xprt); 193261067Smav } 194177633Sdfr return (NULL); 195177633Sdfr} 196177633Sdfr 197177633Sdfr/* 198177633Sdfr * Create a new transport for a socket optained via soaccept(). 199177633Sdfr */ 200177633SdfrSVCXPRT * 201177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 202177633Sdfr{ 203177633Sdfr SVCXPRT *xprt = NULL; 204177633Sdfr struct cf_conn *cd = NULL; 205177633Sdfr struct sockaddr* sa = NULL; 206180025Sdfr struct sockopt opt; 207180025Sdfr int one = 1; 208177633Sdfr int error; 209177633Sdfr 210180025Sdfr bzero(&opt, sizeof(struct sockopt)); 211180025Sdfr opt.sopt_dir = SOPT_SET; 212180025Sdfr opt.sopt_level = SOL_SOCKET; 213180025Sdfr opt.sopt_name = SO_KEEPALIVE; 214180025Sdfr opt.sopt_val = &one; 215180025Sdfr opt.sopt_valsize = sizeof(one); 216180025Sdfr error = sosetopt(so, &opt); 217196503Szec if (error) { 218180025Sdfr return (NULL); 219196503Szec } 220180025Sdfr 221180025Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 222180025Sdfr bzero(&opt, sizeof(struct sockopt)); 223180025Sdfr opt.sopt_dir = SOPT_SET; 224180025Sdfr opt.sopt_level = IPPROTO_TCP; 225180025Sdfr opt.sopt_name = TCP_NODELAY; 226180025Sdfr opt.sopt_val = &one; 227180025Sdfr opt.sopt_valsize = sizeof(one); 228180025Sdfr error = sosetopt(so, &opt); 229196503Szec if (error) { 230180025Sdfr return (NULL); 231196503Szec } 232180025Sdfr } 233180025Sdfr 234177633Sdfr cd = mem_alloc(sizeof(*cd)); 235177633Sdfr cd->strm_stat = XPRT_IDLE; 236177633Sdfr 237184588Sdfr xprt = svc_xprt_alloc(); 238184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 239177633Sdfr xprt->xp_pool = pool; 240177633Sdfr xprt->xp_socket = so; 241177633Sdfr xprt->xp_p1 = cd; 242177633Sdfr xprt->xp_p2 = NULL; 243177633Sdfr xprt->xp_ops = &svc_vc_ops; 244177633Sdfr 245184588Sdfr /* 246184588Sdfr * See http://www.connectathon.org/talks96/nfstcp.pdf - client 247184588Sdfr * has a 5 minute timer, server has a 6 minute timer. 248184588Sdfr */ 249184588Sdfr xprt->xp_idletimeout = 6 * 60; 250177633Sdfr 251184588Sdfr memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 252184588Sdfr 253177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 254177633Sdfr if (error) 255177633Sdfr goto cleanup_svc_vc_create; 256177633Sdfr 257184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 258177633Sdfr free(sa, M_SONAME); 259177633Sdfr 260177633Sdfr xprt_register(xprt); 261177633Sdfr 262177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 263193436Srmacklem xprt->xp_upcallset = 1; 264193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 265177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 266177633Sdfr 267177633Sdfr /* 268177633Sdfr * Throw the transport into the active list in case it already 269177633Sdfr * has some data buffered. 270177633Sdfr */ 271184588Sdfr sx_xlock(&xprt->xp_lock); 272177633Sdfr xprt_active(xprt); 273184588Sdfr sx_xunlock(&xprt->xp_lock); 274177633Sdfr 275177633Sdfr return (xprt); 276177633Sdfrcleanup_svc_vc_create: 277177633Sdfr if (xprt) { 278261067Smav sx_destroy(&xprt->xp_lock); 279261067Smav svc_xprt_free(xprt); 280177633Sdfr } 281177633Sdfr if (cd) 282177633Sdfr mem_free(cd, sizeof(*cd)); 283177633Sdfr return (NULL); 284177633Sdfr} 285177633Sdfr 286177633Sdfr/* 287261058Smav * Create a new transport for a backchannel on a clnt_vc socket. 288261058Smav */ 289261058SmavSVCXPRT * 290261058Smavsvc_vc_create_backchannel(SVCPOOL *pool) 291261058Smav{ 292261058Smav SVCXPRT *xprt = NULL; 293261058Smav struct cf_conn *cd = NULL; 294261058Smav 295261058Smav cd = mem_alloc(sizeof(*cd)); 296261058Smav cd->strm_stat = XPRT_IDLE; 297261058Smav 298261058Smav xprt = svc_xprt_alloc(); 299261058Smav sx_init(&xprt->xp_lock, "xprt->xp_lock"); 300261058Smav xprt->xp_pool = pool; 301261058Smav xprt->xp_socket = NULL; 302261058Smav xprt->xp_p1 = cd; 303261058Smav xprt->xp_p2 = NULL; 304261058Smav xprt->xp_ops = &svc_vc_backchannel_ops; 305261058Smav return (xprt); 306261058Smav} 307261058Smav 308261058Smav/* 309177633Sdfr * This does all of the accept except the final call to soaccept. The 310177633Sdfr * caller will call soaccept after dropping its locks (soaccept may 311177633Sdfr * call malloc). 312177633Sdfr */ 313177633Sdfrint 314177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop) 315177633Sdfr{ 316177633Sdfr int error = 0; 317177633Sdfr struct socket *so; 318177633Sdfr 319177633Sdfr if ((head->so_options & SO_ACCEPTCONN) == 0) { 320177633Sdfr error = EINVAL; 321177633Sdfr goto done; 322177633Sdfr } 323177633Sdfr#ifdef MAC 324193509Srwatson error = mac_socket_check_accept(curthread->td_ucred, head); 325177633Sdfr if (error != 0) 326177633Sdfr goto done; 327177633Sdfr#endif 328177633Sdfr ACCEPT_LOCK(); 329177633Sdfr if (TAILQ_EMPTY(&head->so_comp)) { 330177633Sdfr ACCEPT_UNLOCK(); 331177633Sdfr error = EWOULDBLOCK; 332177633Sdfr goto done; 333177633Sdfr } 334177633Sdfr so = TAILQ_FIRST(&head->so_comp); 335177633Sdfr KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 336177633Sdfr KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 337177633Sdfr 338177633Sdfr /* 339177633Sdfr * Before changing the flags on the socket, we have to bump the 340177633Sdfr * reference count. Otherwise, if the protocol calls sofree(), 341177633Sdfr * the socket will be released due to a zero refcount. 342177633Sdfr * XXX might not need soref() since this is simpler than kern_accept. 343177633Sdfr */ 344177633Sdfr SOCK_LOCK(so); /* soref() and so_state update */ 345177633Sdfr soref(so); /* file descriptor reference */ 346177633Sdfr 347177633Sdfr TAILQ_REMOVE(&head->so_comp, so, so_list); 348177633Sdfr head->so_qlen--; 349177633Sdfr so->so_state |= (head->so_state & SS_NBIO); 350177633Sdfr so->so_qstate &= ~SQ_COMP; 351177633Sdfr so->so_head = NULL; 352177633Sdfr 353177633Sdfr SOCK_UNLOCK(so); 354177633Sdfr ACCEPT_UNLOCK(); 355177633Sdfr 356177633Sdfr *sop = so; 357177633Sdfr 358177633Sdfr /* connection has been removed from the listen queue */ 359177633Sdfr KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 360177633Sdfrdone: 361177633Sdfr return (error); 362177633Sdfr} 363177633Sdfr 364177633Sdfr/*ARGSUSED*/ 365177633Sdfrstatic bool_t 366184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 367184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 368177633Sdfr{ 369177633Sdfr struct socket *so = NULL; 370177633Sdfr struct sockaddr *sa = NULL; 371177633Sdfr int error; 372194407Srmacklem SVCXPRT *new_xprt; 373177633Sdfr 374177633Sdfr /* 375177633Sdfr * The socket upcall calls xprt_active() which will eventually 376177633Sdfr * cause the server to call us here. We attempt to accept a 377177633Sdfr * connection from the socket and turn it into a new 378177633Sdfr * transport. If the accept fails, we have drained all pending 379177633Sdfr * connections so we call xprt_inactive(). 380177633Sdfr */ 381184588Sdfr sx_xlock(&xprt->xp_lock); 382177633Sdfr 383177633Sdfr error = svc_vc_accept(xprt->xp_socket, &so); 384177633Sdfr 385177633Sdfr if (error == EWOULDBLOCK) { 386184588Sdfr /* 387184588Sdfr * We must re-test for new connections after taking 388184588Sdfr * the lock to protect us in the case where a new 389184588Sdfr * connection arrives after our call to accept fails 390261059Smav * with EWOULDBLOCK. 391184588Sdfr */ 392184588Sdfr ACCEPT_LOCK(); 393184588Sdfr if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 394261065Smav xprt_inactive_self(xprt); 395184588Sdfr ACCEPT_UNLOCK(); 396184588Sdfr sx_xunlock(&xprt->xp_lock); 397177633Sdfr return (FALSE); 398177633Sdfr } 399177633Sdfr 400177633Sdfr if (error) { 401177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 402193436Srmacklem if (xprt->xp_upcallset) { 403193436Srmacklem xprt->xp_upcallset = 0; 404193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 405193436Srmacklem } 406177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 407261065Smav xprt_inactive_self(xprt); 408184588Sdfr sx_xunlock(&xprt->xp_lock); 409177633Sdfr return (FALSE); 410177633Sdfr } 411177633Sdfr 412184588Sdfr sx_xunlock(&xprt->xp_lock); 413177633Sdfr 414177633Sdfr sa = 0; 415177633Sdfr error = soaccept(so, &sa); 416177633Sdfr 417177633Sdfr if (error) { 418177633Sdfr /* 419177633Sdfr * XXX not sure if I need to call sofree or soclose here. 420177633Sdfr */ 421177633Sdfr if (sa) 422177633Sdfr free(sa, M_SONAME); 423177633Sdfr return (FALSE); 424177633Sdfr } 425177633Sdfr 426177633Sdfr /* 427177633Sdfr * svc_vc_create_conn will call xprt_register - we don't need 428194407Srmacklem * to do anything with the new connection except derefence it. 429177633Sdfr */ 430194407Srmacklem new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 431194407Srmacklem if (!new_xprt) { 432180025Sdfr soclose(so); 433194407Srmacklem } else { 434194407Srmacklem SVC_RELEASE(new_xprt); 435194407Srmacklem } 436180025Sdfr 437177633Sdfr free(sa, M_SONAME); 438177633Sdfr 439177633Sdfr return (FALSE); /* there is never an rpc msg to be processed */ 440177633Sdfr} 441177633Sdfr 442177633Sdfr/*ARGSUSED*/ 443177633Sdfrstatic enum xprt_stat 444177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt) 445177633Sdfr{ 446177633Sdfr 447177633Sdfr return (XPRT_IDLE); 448177633Sdfr} 449177633Sdfr 450177633Sdfrstatic void 451177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt) 452177633Sdfr{ 453177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 454193436Srmacklem if (xprt->xp_upcallset) { 455193436Srmacklem xprt->xp_upcallset = 0; 456193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 457193436Srmacklem } 458177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 459177633Sdfr 460177633Sdfr if (xprt->xp_socket) 461177633Sdfr (void)soclose(xprt->xp_socket); 462177633Sdfr 463184588Sdfr if (xprt->xp_netid) 464184588Sdfr (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 465184588Sdfr svc_xprt_free(xprt); 466177633Sdfr} 467177633Sdfr 468177633Sdfrstatic void 469177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 470177633Sdfr{ 471177633Sdfr 472177633Sdfr svc_vc_destroy_common(xprt); 473177633Sdfr} 474177633Sdfr 475177633Sdfrstatic void 476177633Sdfrsvc_vc_destroy(SVCXPRT *xprt) 477177633Sdfr{ 478177633Sdfr struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 479177633Sdfr 480177633Sdfr svc_vc_destroy_common(xprt); 481177633Sdfr 482177633Sdfr if (cd->mreq) 483177633Sdfr m_freem(cd->mreq); 484177633Sdfr if (cd->mpending) 485177633Sdfr m_freem(cd->mpending); 486177633Sdfr mem_free(cd, sizeof(*cd)); 487177633Sdfr} 488177633Sdfr 489261058Smavstatic void 490261058Smavsvc_vc_backchannel_destroy(SVCXPRT *xprt) 491261058Smav{ 492261058Smav struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 493261058Smav struct mbuf *m, *m2; 494261058Smav 495261058Smav svc_xprt_free(xprt); 496261058Smav m = cd->mreq; 497261058Smav while (m != NULL) { 498261058Smav m2 = m; 499261058Smav m = m->m_nextpkt; 500261058Smav m_freem(m2); 501261058Smav } 502261058Smav mem_free(cd, sizeof(*cd)); 503261058Smav} 504261058Smav 505177633Sdfr/*ARGSUSED*/ 506177633Sdfrstatic bool_t 507177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 508177633Sdfr{ 509177633Sdfr return (FALSE); 510177633Sdfr} 511177633Sdfr 512177633Sdfrstatic bool_t 513177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 514177633Sdfr{ 515177633Sdfr 516177633Sdfr return (FALSE); 517177633Sdfr} 518177633Sdfr 519261058Smavstatic bool_t 520261058Smavsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 521261058Smav{ 522261058Smav 523261058Smav return (FALSE); 524261058Smav} 525261058Smav 526177633Sdfrstatic enum xprt_stat 527177633Sdfrsvc_vc_stat(SVCXPRT *xprt) 528177633Sdfr{ 529177633Sdfr struct cf_conn *cd; 530177633Sdfr 531177633Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 532177633Sdfr 533177633Sdfr if (cd->strm_stat == XPRT_DIED) 534177633Sdfr return (XPRT_DIED); 535177633Sdfr 536261059Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) 537261059Smav return (XPRT_MOREREQS); 538177633Sdfr 539184588Sdfr if (soreadable(xprt->xp_socket)) 540184588Sdfr return (XPRT_MOREREQS); 541184588Sdfr 542177633Sdfr return (XPRT_IDLE); 543177633Sdfr} 544177633Sdfr 545261067Smavstatic bool_t 546261067Smavsvc_vc_ack(SVCXPRT *xprt, uint32_t *ack) 547261067Smav{ 548261067Smav 549261067Smav *ack = atomic_load_acq_32(&xprt->xp_snt_cnt); 550261067Smav *ack -= xprt->xp_socket->so_snd.sb_cc; 551261067Smav return (TRUE); 552261067Smav} 553261067Smav 554261058Smavstatic enum xprt_stat 555261058Smavsvc_vc_backchannel_stat(SVCXPRT *xprt) 556261058Smav{ 557261058Smav struct cf_conn *cd; 558261058Smav 559261058Smav cd = (struct cf_conn *)(xprt->xp_p1); 560261058Smav 561261058Smav if (cd->mreq != NULL) 562261058Smav return (XPRT_MOREREQS); 563261058Smav 564261058Smav return (XPRT_IDLE); 565261058Smav} 566261058Smav 567261059Smav/* 568261059Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it, 569261059Smav * leaving the result in cd->mreq. If we don't have a complete record, leave 570261059Smav * the partial result in cd->mreq and try to read more from the socket. 571261059Smav */ 572261062Smavstatic int 573261059Smavsvc_vc_process_pending(SVCXPRT *xprt) 574261059Smav{ 575261059Smav struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 576261059Smav struct socket *so = xprt->xp_socket; 577261059Smav struct mbuf *m; 578261059Smav 579261059Smav /* 580261059Smav * If cd->resid is non-zero, we have part of the 581261059Smav * record already, otherwise we are expecting a record 582261059Smav * marker. 583261059Smav */ 584261059Smav if (!cd->resid && cd->mpending) { 585261059Smav /* 586261059Smav * See if there is enough data buffered to 587261059Smav * make up a record marker. Make sure we can 588261059Smav * handle the case where the record marker is 589261059Smav * split across more than one mbuf. 590261059Smav */ 591261059Smav size_t n = 0; 592261059Smav uint32_t header; 593261059Smav 594261059Smav m = cd->mpending; 595261059Smav while (n < sizeof(uint32_t) && m) { 596261059Smav n += m->m_len; 597261059Smav m = m->m_next; 598261059Smav } 599261059Smav if (n < sizeof(uint32_t)) { 600261059Smav so->so_rcv.sb_lowat = sizeof(uint32_t) - n; 601261062Smav return (FALSE); 602261059Smav } 603261059Smav m_copydata(cd->mpending, 0, sizeof(header), 604261059Smav (char *)&header); 605261059Smav header = ntohl(header); 606261059Smav cd->eor = (header & 0x80000000) != 0; 607261059Smav cd->resid = header & 0x7fffffff; 608261059Smav m_adj(cd->mpending, sizeof(uint32_t)); 609261059Smav } 610261059Smav 611261059Smav /* 612261059Smav * Start pulling off mbufs from cd->mpending 613261059Smav * until we either have a complete record or 614261059Smav * we run out of data. We use m_split to pull 615261059Smav * data - it will pull as much as possible and 616261059Smav * split the last mbuf if necessary. 617261059Smav */ 618261059Smav while (cd->mpending && cd->resid) { 619261059Smav m = cd->mpending; 620261059Smav if (cd->mpending->m_next 621261059Smav || cd->mpending->m_len > cd->resid) 622261059Smav cd->mpending = m_split(cd->mpending, 623261059Smav cd->resid, M_WAITOK); 624261059Smav else 625261059Smav cd->mpending = NULL; 626261059Smav if (cd->mreq) 627261059Smav m_last(cd->mreq)->m_next = m; 628261059Smav else 629261059Smav cd->mreq = m; 630261059Smav while (m) { 631261059Smav cd->resid -= m->m_len; 632261059Smav m = m->m_next; 633261059Smav } 634261059Smav } 635261059Smav 636261064Smav /* 637261064Smav * Block receive upcalls if we have more data pending, 638261064Smav * otherwise report our need. 639261064Smav */ 640261064Smav if (cd->mpending) 641261064Smav so->so_rcv.sb_lowat = INT_MAX; 642261064Smav else 643261064Smav so->so_rcv.sb_lowat = 644261064Smav imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2)); 645261062Smav return (TRUE); 646261059Smav} 647261059Smav 648177633Sdfrstatic bool_t 649184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 650184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 651177633Sdfr{ 652177633Sdfr struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 653177633Sdfr struct uio uio; 654177633Sdfr struct mbuf *m; 655261059Smav struct socket* so = xprt->xp_socket; 656184588Sdfr XDR xdrs; 657177633Sdfr int error, rcvflag; 658177633Sdfr 659184588Sdfr /* 660184588Sdfr * Serialise access to the socket and our own record parsing 661184588Sdfr * state. 662184588Sdfr */ 663184588Sdfr sx_xlock(&xprt->xp_lock); 664184588Sdfr 665177633Sdfr for (;;) { 666261059Smav /* If we have no request ready, check pending queue. */ 667261059Smav while (cd->mpending && 668261062Smav (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) { 669261062Smav if (!svc_vc_process_pending(xprt)) 670261062Smav break; 671261062Smav } 672177633Sdfr 673261059Smav /* Process and return complete request in cd->mreq. */ 674261059Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) { 675177633Sdfr 676261059Smav xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 677261059Smav cd->mreq = NULL; 678261059Smav 679261059Smav /* Check for next request in a pending queue. */ 680261059Smav svc_vc_process_pending(xprt); 681261059Smav if (cd->mreq == NULL || cd->resid != 0) { 682261059Smav SOCKBUF_LOCK(&so->so_rcv); 683261059Smav if (!soreadable(so)) 684261065Smav xprt_inactive_self(xprt); 685261059Smav SOCKBUF_UNLOCK(&so->so_rcv); 686177633Sdfr } 687177633Sdfr 688261059Smav sx_xunlock(&xprt->xp_lock); 689177633Sdfr 690261059Smav if (! xdr_callmsg(&xdrs, msg)) { 691261059Smav XDR_DESTROY(&xdrs); 692261059Smav return (FALSE); 693261059Smav } 694184588Sdfr 695261059Smav *addrp = NULL; 696261059Smav *mp = xdrmbuf_getall(&xdrs); 697261059Smav XDR_DESTROY(&xdrs); 698177633Sdfr 699261059Smav return (TRUE); 700177633Sdfr } 701177633Sdfr 702177633Sdfr /* 703177633Sdfr * The socket upcall calls xprt_active() which will eventually 704177633Sdfr * cause the server to call us here. We attempt to 705177633Sdfr * read as much as possible from the socket and put 706177633Sdfr * the result in cd->mpending. If the read fails, 707177633Sdfr * we have drained both cd->mpending and the socket so 708177633Sdfr * we can call xprt_inactive(). 709177633Sdfr */ 710177633Sdfr uio.uio_resid = 1000000000; 711177633Sdfr uio.uio_td = curthread; 712177633Sdfr m = NULL; 713177633Sdfr rcvflag = MSG_DONTWAIT; 714261059Smav error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 715177633Sdfr 716177633Sdfr if (error == EWOULDBLOCK) { 717184588Sdfr /* 718184588Sdfr * We must re-test for readability after 719184588Sdfr * taking the lock to protect us in the case 720184588Sdfr * where a new packet arrives on the socket 721184588Sdfr * after our call to soreceive fails with 722261059Smav * EWOULDBLOCK. 723184588Sdfr */ 724261059Smav SOCKBUF_LOCK(&so->so_rcv); 725261059Smav if (!soreadable(so)) 726261065Smav xprt_inactive_self(xprt); 727261059Smav SOCKBUF_UNLOCK(&so->so_rcv); 728184588Sdfr sx_xunlock(&xprt->xp_lock); 729177633Sdfr return (FALSE); 730177633Sdfr } 731177633Sdfr 732177633Sdfr if (error) { 733261059Smav SOCKBUF_LOCK(&so->so_rcv); 734193436Srmacklem if (xprt->xp_upcallset) { 735193436Srmacklem xprt->xp_upcallset = 0; 736261059Smav soupcall_clear(so, SO_RCV); 737193436Srmacklem } 738261059Smav SOCKBUF_UNLOCK(&so->so_rcv); 739261065Smav xprt_inactive_self(xprt); 740177633Sdfr cd->strm_stat = XPRT_DIED; 741184588Sdfr sx_xunlock(&xprt->xp_lock); 742177633Sdfr return (FALSE); 743177633Sdfr } 744177633Sdfr 745177633Sdfr if (!m) { 746177633Sdfr /* 747177633Sdfr * EOF - the other end has closed the socket. 748177633Sdfr */ 749261065Smav xprt_inactive_self(xprt); 750177633Sdfr cd->strm_stat = XPRT_DIED; 751184588Sdfr sx_xunlock(&xprt->xp_lock); 752177633Sdfr return (FALSE); 753177633Sdfr } 754177633Sdfr 755177633Sdfr if (cd->mpending) 756177633Sdfr m_last(cd->mpending)->m_next = m; 757177633Sdfr else 758177633Sdfr cd->mpending = m; 759177633Sdfr } 760177633Sdfr} 761177633Sdfr 762177633Sdfrstatic bool_t 763261058Smavsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 764261058Smav struct sockaddr **addrp, struct mbuf **mp) 765261058Smav{ 766261058Smav struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 767261058Smav struct ct_data *ct; 768261058Smav struct mbuf *m; 769261058Smav XDR xdrs; 770261058Smav 771261058Smav sx_xlock(&xprt->xp_lock); 772261058Smav ct = (struct ct_data *)xprt->xp_p2; 773261058Smav if (ct == NULL) { 774261058Smav sx_xunlock(&xprt->xp_lock); 775261058Smav return (FALSE); 776261058Smav } 777261058Smav mtx_lock(&ct->ct_lock); 778261058Smav m = cd->mreq; 779261058Smav if (m == NULL) { 780261065Smav xprt_inactive_self(xprt); 781261058Smav mtx_unlock(&ct->ct_lock); 782261058Smav sx_xunlock(&xprt->xp_lock); 783261058Smav return (FALSE); 784261058Smav } 785261058Smav cd->mreq = m->m_nextpkt; 786261058Smav mtx_unlock(&ct->ct_lock); 787261058Smav sx_xunlock(&xprt->xp_lock); 788261058Smav 789261058Smav xdrmbuf_create(&xdrs, m, XDR_DECODE); 790261058Smav if (! xdr_callmsg(&xdrs, msg)) { 791261058Smav XDR_DESTROY(&xdrs); 792261058Smav return (FALSE); 793261058Smav } 794261058Smav *addrp = NULL; 795261058Smav *mp = xdrmbuf_getall(&xdrs); 796261058Smav XDR_DESTROY(&xdrs); 797261058Smav return (TRUE); 798261058Smav} 799261058Smav 800261058Smavstatic bool_t 801184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 802261067Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 803177633Sdfr{ 804177633Sdfr XDR xdrs; 805177633Sdfr struct mbuf *mrep; 806184588Sdfr bool_t stat = TRUE; 807261067Smav int error, len; 808177633Sdfr 809177633Sdfr /* 810177633Sdfr * Leave space for record mark. 811177633Sdfr */ 812177633Sdfr MGETHDR(mrep, M_WAIT, MT_DATA); 813177633Sdfr mrep->m_len = 0; 814177633Sdfr mrep->m_data += sizeof(uint32_t); 815177633Sdfr 816184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 817184588Sdfr 818184588Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 819184588Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 820184588Sdfr if (!xdr_replymsg(&xdrs, msg)) 821184588Sdfr stat = FALSE; 822184588Sdfr else 823184588Sdfr xdrmbuf_append(&xdrs, m); 824184588Sdfr } else { 825184588Sdfr stat = xdr_replymsg(&xdrs, msg); 826184588Sdfr } 827184588Sdfr 828184588Sdfr if (stat) { 829177633Sdfr m_fixhdr(mrep); 830177633Sdfr 831177633Sdfr /* 832177633Sdfr * Prepend a record marker containing the reply length. 833177633Sdfr */ 834177633Sdfr M_PREPEND(mrep, sizeof(uint32_t), M_WAIT); 835261067Smav len = mrep->m_pkthdr.len; 836177633Sdfr *mtod(mrep, uint32_t *) = 837261067Smav htonl(0x80000000 | (len - sizeof(uint32_t))); 838261067Smav atomic_add_acq_32(&xprt->xp_snd_cnt, len); 839177633Sdfr error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 840177633Sdfr 0, curthread); 841177633Sdfr if (!error) { 842261067Smav atomic_add_rel_32(&xprt->xp_snt_cnt, len); 843261067Smav if (seq) 844261067Smav *seq = xprt->xp_snd_cnt; 845177633Sdfr stat = TRUE; 846261067Smav } else 847261067Smav atomic_subtract_32(&xprt->xp_snd_cnt, len); 848177633Sdfr } else { 849177633Sdfr m_freem(mrep); 850177633Sdfr } 851177633Sdfr 852184588Sdfr XDR_DESTROY(&xdrs); 853177633Sdfr xprt->xp_p2 = NULL; 854177633Sdfr 855177633Sdfr return (stat); 856177633Sdfr} 857177633Sdfr 858177633Sdfrstatic bool_t 859261058Smavsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 860261067Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 861261058Smav{ 862261058Smav struct ct_data *ct; 863261058Smav XDR xdrs; 864261058Smav struct mbuf *mrep; 865261058Smav bool_t stat = TRUE; 866261058Smav int error; 867261058Smav 868261058Smav /* 869261058Smav * Leave space for record mark. 870261058Smav */ 871261058Smav MGETHDR(mrep, M_WAITOK, MT_DATA); 872261058Smav mrep->m_len = 0; 873261058Smav mrep->m_data += sizeof(uint32_t); 874261058Smav 875261058Smav xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 876261058Smav 877261058Smav if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 878261058Smav msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 879261058Smav if (!xdr_replymsg(&xdrs, msg)) 880261058Smav stat = FALSE; 881261058Smav else 882261058Smav xdrmbuf_append(&xdrs, m); 883261058Smav } else { 884261058Smav stat = xdr_replymsg(&xdrs, msg); 885261058Smav } 886261058Smav 887261058Smav if (stat) { 888261058Smav m_fixhdr(mrep); 889261058Smav 890261058Smav /* 891261058Smav * Prepend a record marker containing the reply length. 892261058Smav */ 893261058Smav M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 894261058Smav *mtod(mrep, uint32_t *) = 895261058Smav htonl(0x80000000 | (mrep->m_pkthdr.len 896261058Smav - sizeof(uint32_t))); 897261058Smav sx_xlock(&xprt->xp_lock); 898261058Smav ct = (struct ct_data *)xprt->xp_p2; 899261058Smav if (ct != NULL) 900261058Smav error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 901261058Smav 0, curthread); 902261058Smav else 903261058Smav error = EPIPE; 904261058Smav sx_xunlock(&xprt->xp_lock); 905261058Smav if (!error) { 906261058Smav stat = TRUE; 907261058Smav } 908261058Smav } else { 909261058Smav m_freem(mrep); 910261058Smav } 911261058Smav 912261058Smav XDR_DESTROY(&xdrs); 913261058Smav 914261058Smav return (stat); 915261058Smav} 916261058Smav 917261058Smavstatic bool_t 918177633Sdfrsvc_vc_null() 919177633Sdfr{ 920177633Sdfr 921177633Sdfr return (FALSE); 922177633Sdfr} 923177633Sdfr 924193272Sjhbstatic int 925177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 926177633Sdfr{ 927177633Sdfr SVCXPRT *xprt = (SVCXPRT *) arg; 928177633Sdfr 929261059Smav if (soreadable(xprt->xp_socket)) 930261059Smav xprt_active(xprt); 931193272Sjhb return (SU_OK); 932177633Sdfr} 933177633Sdfr 934177633Sdfr#if 0 935177633Sdfr/* 936177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv 937177633Sdfr * and rpc.yppasswdd on AF_LOCAL. 938177633Sdfr */ 939177633Sdfrint 940177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 941177633Sdfr int sock, ret; 942177633Sdfr gid_t egid; 943177633Sdfr uid_t euid; 944177633Sdfr struct sockaddr *sa; 945177633Sdfr 946177633Sdfr sock = transp->xp_fd; 947184588Sdfr sa = (struct sockaddr *)transp->xp_rtaddr; 948177633Sdfr if (sa->sa_family == AF_LOCAL) { 949177633Sdfr ret = getpeereid(sock, &euid, &egid); 950177633Sdfr if (ret == 0) 951177633Sdfr *uid = euid; 952177633Sdfr return (ret); 953177633Sdfr } else 954177633Sdfr return (-1); 955177633Sdfr} 956177633Sdfr#endif 957