The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/rpc/svc_vc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $  */
    2 
    3 /*-
    4  * SPDX-License-Identifier: BSD-3-Clause
    5  *
    6  * Copyright (c) 2009, Sun Microsystems, Inc.
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without 
   10  * modification, are permitted provided that the following conditions are met:
   11  * - Redistributions of source code must retain the above copyright notice, 
   12  *   this list of conditions and the following disclaimer.
   13  * - Redistributions in binary form must reproduce the above copyright notice, 
   14  *   this list of conditions and the following disclaimer in the documentation 
   15  *   and/or other materials provided with the distribution.
   16  * - Neither the name of Sun Microsystems, Inc. nor the names of its 
   17  *   contributors may be used to endorse or promote products derived 
   18  *   from this software without specific prior written permission.
   19  * 
   20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
   21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
   23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
   24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #if defined(LIBC_SCCS) && !defined(lint)
   34 static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
   35 static char *sccsid = "@(#)svc_tcp.c    2.2 88/08/01 4.0 RPCSRC";
   36 #endif
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD$");
   39 
   40 /*
   41  * svc_vc.c, Server side for Connection Oriented based RPC. 
   42  *
   43  * Actually implements two flavors of transporter -
   44  * a tcp rendezvouser (a listner and connection establisher)
   45  * and a record/tcp stream.
   46  */
   47 
   48 #include "opt_kern_tls.h"
   49 
   50 #include <sys/param.h>
   51 #include <sys/limits.h>
   52 #include <sys/lock.h>
   53 #include <sys/kernel.h>
   54 #include <sys/ktls.h>
   55 #include <sys/malloc.h>
   56 #include <sys/mbuf.h>
   57 #include <sys/mutex.h>
   58 #include <sys/proc.h>
   59 #include <sys/protosw.h>
   60 #include <sys/queue.h>
   61 #include <sys/socket.h>
   62 #include <sys/socketvar.h>
   63 #include <sys/sx.h>
   64 #include <sys/systm.h>
   65 #include <sys/uio.h>
   66 
   67 #include <net/vnet.h>
   68 
   69 #include <netinet/tcp.h>
   70 
   71 #include <rpc/rpc.h>
   72 #include <rpc/rpcsec_tls.h>
   73 
   74 #include <rpc/krpc.h>
   75 #include <rpc/rpc_com.h>
   76 
   77 #include <security/mac/mac_framework.h>
   78 
   79 static bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
   80     struct sockaddr **, struct mbuf **);
   81 static enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
   82 static void svc_vc_rendezvous_destroy(SVCXPRT *);
   83 static bool_t svc_vc_null(void);
   84 static void svc_vc_destroy(SVCXPRT *);
   85 static enum xprt_stat svc_vc_stat(SVCXPRT *);
   86 static bool_t svc_vc_ack(SVCXPRT *, uint32_t *);
   87 static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
   88     struct sockaddr **, struct mbuf **);
   89 static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
   90     struct sockaddr *, struct mbuf *, uint32_t *seq);
   91 static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
   92 static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
   93     void *in);
   94 static void svc_vc_backchannel_destroy(SVCXPRT *);
   95 static enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
   96 static bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
   97     struct sockaddr **, struct mbuf **);
   98 static bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
   99     struct sockaddr *, struct mbuf *, uint32_t *);
  100 static bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
  101     void *in);
  102 static SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
  103     struct sockaddr *raddr);
  104 static int svc_vc_accept(struct socket *head, struct socket **sop);
  105 static int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
  106 static int svc_vc_rendezvous_soupcall(struct socket *, void *, int);
  107 
  108 static const struct xp_ops svc_vc_rendezvous_ops = {
  109         .xp_recv =      svc_vc_rendezvous_recv,
  110         .xp_stat =      svc_vc_rendezvous_stat,
  111         .xp_reply =     (bool_t (*)(SVCXPRT *, struct rpc_msg *,
  112                 struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null,
  113         .xp_destroy =   svc_vc_rendezvous_destroy,
  114         .xp_control =   svc_vc_rendezvous_control
  115 };
  116 
  117 static const struct xp_ops svc_vc_ops = {
  118         .xp_recv =      svc_vc_recv,
  119         .xp_stat =      svc_vc_stat,
  120         .xp_ack =       svc_vc_ack,
  121         .xp_reply =     svc_vc_reply,
  122         .xp_destroy =   svc_vc_destroy,
  123         .xp_control =   svc_vc_control
  124 };
  125 
  126 static const struct xp_ops svc_vc_backchannel_ops = {
  127         .xp_recv =      svc_vc_backchannel_recv,
  128         .xp_stat =      svc_vc_backchannel_stat,
  129         .xp_reply =     svc_vc_backchannel_reply,
  130         .xp_destroy =   svc_vc_backchannel_destroy,
  131         .xp_control =   svc_vc_backchannel_control
  132 };
  133 
  134 /*
  135  * Usage:
  136  *      xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
  137  *
  138  * Creates, registers, and returns a (rpc) tcp based transporter.
  139  * Once *xprt is initialized, it is registered as a transporter
  140  * see (svc.h, xprt_register).  This routine returns
  141  * a NULL if a problem occurred.
  142  *
  143  * The filedescriptor passed in is expected to refer to a bound, but
  144  * not yet connected socket.
  145  *
  146  * Since streams do buffered io similar to stdio, the caller can specify
  147  * how big the send and receive buffers are via the second and third parms;
  148  * 0 => use the system default.
  149  */
  150 SVCXPRT *
  151 svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
  152     size_t recvsize)
  153 {
  154         SVCXPRT *xprt;
  155         struct sockaddr* sa;
  156         int error;
  157 
  158         SOCK_LOCK(so);
  159         if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) {
  160                 SOCK_UNLOCK(so);
  161                 CURVNET_SET(so->so_vnet);
  162                 error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
  163                 CURVNET_RESTORE();
  164                 if (error)
  165                         return (NULL);
  166                 xprt = svc_vc_create_conn(pool, so, sa);
  167                 free(sa, M_SONAME);
  168                 return (xprt);
  169         }
  170         SOCK_UNLOCK(so);
  171 
  172         xprt = svc_xprt_alloc();
  173         sx_init(&xprt->xp_lock, "xprt->xp_lock");
  174         xprt->xp_pool = pool;
  175         xprt->xp_socket = so;
  176         xprt->xp_p1 = NULL;
  177         xprt->xp_p2 = NULL;
  178         xprt->xp_ops = &svc_vc_rendezvous_ops;
  179 
  180         CURVNET_SET(so->so_vnet);
  181         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
  182         CURVNET_RESTORE();
  183         if (error) {
  184                 goto cleanup_svc_vc_create;
  185         }
  186 
  187         memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
  188         free(sa, M_SONAME);
  189 
  190         xprt_register(xprt);
  191 
  192         solisten(so, -1, curthread);
  193 
  194         SOLISTEN_LOCK(so);
  195         xprt->xp_upcallset = 1;
  196         solisten_upcall_set(so, svc_vc_rendezvous_soupcall, xprt);
  197         SOLISTEN_UNLOCK(so);
  198 
  199         return (xprt);
  200 
  201 cleanup_svc_vc_create:
  202         sx_destroy(&xprt->xp_lock);
  203         svc_xprt_free(xprt);
  204 
  205         return (NULL);
  206 }
  207 
  208 /*
  209  * Create a new transport for a socket optained via soaccept().
  210  */
  211 SVCXPRT *
  212 svc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
  213 {
  214         SVCXPRT *xprt;
  215         struct cf_conn *cd;
  216         struct sockaddr* sa = NULL;
  217         struct sockopt opt;
  218         int one = 1;
  219         int error;
  220 
  221         bzero(&opt, sizeof(struct sockopt));
  222         opt.sopt_dir = SOPT_SET;
  223         opt.sopt_level = SOL_SOCKET;
  224         opt.sopt_name = SO_KEEPALIVE;
  225         opt.sopt_val = &one;
  226         opt.sopt_valsize = sizeof(one);
  227         error = sosetopt(so, &opt);
  228         if (error) {
  229                 return (NULL);
  230         }
  231 
  232         if (so->so_proto->pr_protocol == IPPROTO_TCP) {
  233                 bzero(&opt, sizeof(struct sockopt));
  234                 opt.sopt_dir = SOPT_SET;
  235                 opt.sopt_level = IPPROTO_TCP;
  236                 opt.sopt_name = TCP_NODELAY;
  237                 opt.sopt_val = &one;
  238                 opt.sopt_valsize = sizeof(one);
  239                 error = sosetopt(so, &opt);
  240                 if (error) {
  241                         return (NULL);
  242                 }
  243         }
  244 
  245         cd = mem_alloc(sizeof(*cd));
  246         cd->strm_stat = XPRT_IDLE;
  247 
  248         xprt = svc_xprt_alloc();
  249         sx_init(&xprt->xp_lock, "xprt->xp_lock");
  250         xprt->xp_pool = pool;
  251         xprt->xp_socket = so;
  252         xprt->xp_p1 = cd;
  253         xprt->xp_p2 = NULL;
  254         xprt->xp_ops = &svc_vc_ops;
  255 
  256         /*
  257          * See http://www.connectathon.org/talks96/nfstcp.pdf - client
  258          * has a 5 minute timer, server has a 6 minute timer.
  259          */
  260         xprt->xp_idletimeout = 6 * 60;
  261 
  262         memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
  263 
  264         CURVNET_SET(so->so_vnet);
  265         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
  266         CURVNET_RESTORE();
  267         if (error)
  268                 goto cleanup_svc_vc_create;
  269 
  270         memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
  271         free(sa, M_SONAME);
  272 
  273         xprt_register(xprt);
  274 
  275         SOCKBUF_LOCK(&so->so_rcv);
  276         xprt->xp_upcallset = 1;
  277         soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
  278         SOCKBUF_UNLOCK(&so->so_rcv);
  279 
  280         /*
  281          * Throw the transport into the active list in case it already
  282          * has some data buffered.
  283          */
  284         sx_xlock(&xprt->xp_lock);
  285         xprt_active(xprt);
  286         sx_xunlock(&xprt->xp_lock);
  287 
  288         return (xprt);
  289 cleanup_svc_vc_create:
  290         sx_destroy(&xprt->xp_lock);
  291         svc_xprt_free(xprt);
  292         mem_free(cd, sizeof(*cd));
  293 
  294         return (NULL);
  295 }
  296 
  297 /*
  298  * Create a new transport for a backchannel on a clnt_vc socket.
  299  */
  300 SVCXPRT *
  301 svc_vc_create_backchannel(SVCPOOL *pool)
  302 {
  303         SVCXPRT *xprt = NULL;
  304         struct cf_conn *cd = NULL;
  305 
  306         cd = mem_alloc(sizeof(*cd));
  307         cd->strm_stat = XPRT_IDLE;
  308 
  309         xprt = svc_xprt_alloc();
  310         sx_init(&xprt->xp_lock, "xprt->xp_lock");
  311         xprt->xp_pool = pool;
  312         xprt->xp_socket = NULL;
  313         xprt->xp_p1 = cd;
  314         xprt->xp_p2 = NULL;
  315         xprt->xp_ops = &svc_vc_backchannel_ops;
  316         return (xprt);
  317 }
  318 
  319 /*
  320  * This does all of the accept except the final call to soaccept. The
  321  * caller will call soaccept after dropping its locks (soaccept may
  322  * call malloc).
  323  */
  324 int
  325 svc_vc_accept(struct socket *head, struct socket **sop)
  326 {
  327         struct socket *so;
  328         int error = 0;
  329         short nbio;
  330 
  331         KASSERT(SOLISTENING(head),
  332             ("%s: socket %p is not listening", __func__, head));
  333 
  334 #ifdef MAC
  335         error = mac_socket_check_accept(curthread->td_ucred, head);
  336         if (error != 0)
  337                 goto done;
  338 #endif
  339         /*
  340          * XXXGL: we want non-blocking semantics.  The socket could be a
  341          * socket created by kernel as well as socket shared with userland,
  342          * so we can't be sure about presense of SS_NBIO.  We also shall not
  343          * toggle it on the socket, since that may surprise userland.  So we
  344          * set SS_NBIO only temporarily.
  345          */
  346         SOLISTEN_LOCK(head);
  347         nbio = head->so_state & SS_NBIO;
  348         head->so_state |= SS_NBIO;
  349         error = solisten_dequeue(head, &so, 0);
  350         head->so_state &= (nbio & ~SS_NBIO);
  351         if (error)
  352                 goto done;
  353 
  354         so->so_state |= nbio;
  355         *sop = so;
  356 
  357         /* connection has been removed from the listen queue */
  358         KNOTE_UNLOCKED(&head->so_rdsel.si_note, 0);
  359 done:
  360         return (error);
  361 }
  362 
  363 /*ARGSUSED*/
  364 static bool_t
  365 svc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
  366     struct sockaddr **addrp, struct mbuf **mp)
  367 {
  368         struct socket *so = NULL;
  369         struct sockaddr *sa = NULL;
  370         int error;
  371         SVCXPRT *new_xprt;
  372 
  373         /*
  374          * The socket upcall calls xprt_active() which will eventually
  375          * cause the server to call us here. We attempt to accept a
  376          * connection from the socket and turn it into a new
  377          * transport. If the accept fails, we have drained all pending
  378          * connections so we call xprt_inactive().
  379          */
  380         sx_xlock(&xprt->xp_lock);
  381 
  382         error = svc_vc_accept(xprt->xp_socket, &so);
  383 
  384         if (error == EWOULDBLOCK) {
  385                 /*
  386                  * We must re-test for new connections after taking
  387                  * the lock to protect us in the case where a new
  388                  * connection arrives after our call to accept fails
  389                  * with EWOULDBLOCK.
  390                  */
  391                 SOLISTEN_LOCK(xprt->xp_socket);
  392                 if (TAILQ_EMPTY(&xprt->xp_socket->sol_comp))
  393                         xprt_inactive_self(xprt);
  394                 SOLISTEN_UNLOCK(xprt->xp_socket);
  395                 sx_xunlock(&xprt->xp_lock);
  396                 return (FALSE);
  397         }
  398 
  399         if (error) {
  400                 SOLISTEN_LOCK(xprt->xp_socket);
  401                 if (xprt->xp_upcallset) {
  402                         xprt->xp_upcallset = 0;
  403                         soupcall_clear(xprt->xp_socket, SO_RCV);
  404                 }
  405                 SOLISTEN_UNLOCK(xprt->xp_socket);
  406                 xprt_inactive_self(xprt);
  407                 sx_xunlock(&xprt->xp_lock);
  408                 return (FALSE);
  409         }
  410 
  411         sx_xunlock(&xprt->xp_lock);
  412 
  413         sa = NULL;
  414         error = soaccept(so, &sa);
  415 
  416         if (error) {
  417                 /*
  418                  * XXX not sure if I need to call sofree or soclose here.
  419                  */
  420                 if (sa)
  421                         free(sa, M_SONAME);
  422                 return (FALSE);
  423         }
  424 
  425         /*
  426          * svc_vc_create_conn will call xprt_register - we don't need
  427          * to do anything with the new connection except derefence it.
  428          */
  429         new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
  430         if (!new_xprt) {
  431                 soclose(so);
  432         } else {
  433                 SVC_RELEASE(new_xprt);
  434         }
  435 
  436         free(sa, M_SONAME);
  437 
  438         return (FALSE); /* there is never an rpc msg to be processed */
  439 }
  440 
  441 /*ARGSUSED*/
  442 static enum xprt_stat
  443 svc_vc_rendezvous_stat(SVCXPRT *xprt)
  444 {
  445 
  446         return (XPRT_IDLE);
  447 }
  448 
  449 static void
  450 svc_vc_destroy_common(SVCXPRT *xprt)
  451 {
  452         enum clnt_stat stat;
  453         uint32_t reterr;
  454 
  455         if (xprt->xp_socket) {
  456                 if ((xprt->xp_tls & (RPCTLS_FLAGS_HANDSHAKE |
  457                     RPCTLS_FLAGS_HANDSHFAIL)) != 0) {
  458                         if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
  459                                 /*
  460                                  * If the upcall fails, the socket has
  461                                  * probably been closed via the rpctlssd
  462                                  * daemon having crashed or been
  463                                  * restarted, so just ignore returned stat.
  464                                  */
  465                                 stat = rpctls_srv_disconnect(xprt->xp_sslsec,
  466                                     xprt->xp_sslusec, xprt->xp_sslrefno,
  467                                     &reterr);
  468                         }
  469                         /* Must sorele() to get rid of reference. */
  470                         CURVNET_SET(xprt->xp_socket->so_vnet);
  471                         SOCK_LOCK(xprt->xp_socket);
  472                         sorele(xprt->xp_socket);
  473                         CURVNET_RESTORE();
  474                 } else
  475                         (void)soclose(xprt->xp_socket);
  476         }
  477 
  478         if (xprt->xp_netid)
  479                 (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
  480         svc_xprt_free(xprt);
  481 }
  482 
  483 static void
  484 svc_vc_rendezvous_destroy(SVCXPRT *xprt)
  485 {
  486 
  487         SOLISTEN_LOCK(xprt->xp_socket);
  488         if (xprt->xp_upcallset) {
  489                 xprt->xp_upcallset = 0;
  490                 solisten_upcall_set(xprt->xp_socket, NULL, NULL);
  491         }
  492         SOLISTEN_UNLOCK(xprt->xp_socket);
  493 
  494         svc_vc_destroy_common(xprt);
  495 }
  496 
  497 static void
  498 svc_vc_destroy(SVCXPRT *xprt)
  499 {
  500         struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
  501         CLIENT *cl = (CLIENT *)xprt->xp_p2;
  502 
  503         SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
  504         if (xprt->xp_upcallset) {
  505                 xprt->xp_upcallset = 0;
  506                 if (xprt->xp_socket->so_rcv.sb_upcall != NULL)
  507                         soupcall_clear(xprt->xp_socket, SO_RCV);
  508         }
  509         SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
  510 
  511         if (cl != NULL)
  512                 CLNT_RELEASE(cl);
  513 
  514         svc_vc_destroy_common(xprt);
  515 
  516         if (cd->mreq)
  517                 m_freem(cd->mreq);
  518         if (cd->mpending)
  519                 m_freem(cd->mpending);
  520         mem_free(cd, sizeof(*cd));
  521 }
  522 
  523 static void
  524 svc_vc_backchannel_destroy(SVCXPRT *xprt)
  525 {
  526         struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
  527         struct mbuf *m, *m2;
  528 
  529         svc_xprt_free(xprt);
  530         m = cd->mreq;
  531         while (m != NULL) {
  532                 m2 = m;
  533                 m = m->m_nextpkt;
  534                 m_freem(m2);
  535         }
  536         mem_free(cd, sizeof(*cd));
  537 }
  538 
  539 /*ARGSUSED*/
  540 static bool_t
  541 svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
  542 {
  543         return (FALSE);
  544 }
  545 
  546 static bool_t
  547 svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
  548 {
  549 
  550         return (FALSE);
  551 }
  552 
  553 static bool_t
  554 svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
  555 {
  556 
  557         return (FALSE);
  558 }
  559 
  560 static enum xprt_stat
  561 svc_vc_stat(SVCXPRT *xprt)
  562 {
  563         struct cf_conn *cd;
  564 
  565         cd = (struct cf_conn *)(xprt->xp_p1);
  566 
  567         if (cd->strm_stat == XPRT_DIED)
  568                 return (XPRT_DIED);
  569 
  570         if (cd->mreq != NULL && cd->resid == 0 && cd->eor)
  571                 return (XPRT_MOREREQS);
  572 
  573         if (soreadable(xprt->xp_socket))
  574                 return (XPRT_MOREREQS);
  575 
  576         return (XPRT_IDLE);
  577 }
  578 
  579 static bool_t
  580 svc_vc_ack(SVCXPRT *xprt, uint32_t *ack)
  581 {
  582 
  583         *ack = atomic_load_acq_32(&xprt->xp_snt_cnt);
  584         *ack -= sbused(&xprt->xp_socket->so_snd);
  585         return (TRUE);
  586 }
  587 
  588 static enum xprt_stat
  589 svc_vc_backchannel_stat(SVCXPRT *xprt)
  590 {
  591         struct cf_conn *cd;
  592 
  593         cd = (struct cf_conn *)(xprt->xp_p1);
  594 
  595         if (cd->mreq != NULL)
  596                 return (XPRT_MOREREQS);
  597 
  598         return (XPRT_IDLE);
  599 }
  600 
  601 /*
  602  * If we have an mbuf chain in cd->mpending, try to parse a record from it,
  603  * leaving the result in cd->mreq. If we don't have a complete record, leave
  604  * the partial result in cd->mreq and try to read more from the socket.
  605  */
  606 static int
  607 svc_vc_process_pending(SVCXPRT *xprt)
  608 {
  609         struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
  610         struct socket *so = xprt->xp_socket;
  611         struct mbuf *m;
  612 
  613         /*
  614          * If cd->resid is non-zero, we have part of the
  615          * record already, otherwise we are expecting a record
  616          * marker.
  617          */
  618         if (!cd->resid && cd->mpending) {
  619                 /*
  620                  * See if there is enough data buffered to
  621                  * make up a record marker. Make sure we can
  622                  * handle the case where the record marker is
  623                  * split across more than one mbuf.
  624                  */
  625                 size_t n = 0;
  626                 uint32_t header;
  627 
  628                 m = cd->mpending;
  629                 while (n < sizeof(uint32_t) && m) {
  630                         n += m->m_len;
  631                         m = m->m_next;
  632                 }
  633                 if (n < sizeof(uint32_t)) {
  634                         so->so_rcv.sb_lowat = sizeof(uint32_t) - n;
  635                         return (FALSE);
  636                 }
  637                 m_copydata(cd->mpending, 0, sizeof(header),
  638                     (char *)&header);
  639                 header = ntohl(header);
  640                 cd->eor = (header & 0x80000000) != 0;
  641                 cd->resid = header & 0x7fffffff;
  642                 m_adj(cd->mpending, sizeof(uint32_t));
  643         }
  644 
  645         /*
  646          * Start pulling off mbufs from cd->mpending
  647          * until we either have a complete record or
  648          * we run out of data. We use m_split to pull
  649          * data - it will pull as much as possible and
  650          * split the last mbuf if necessary.
  651          */
  652         while (cd->mpending && cd->resid) {
  653                 m = cd->mpending;
  654                 if (cd->mpending->m_next
  655                     || cd->mpending->m_len > cd->resid)
  656                         cd->mpending = m_split(cd->mpending,
  657                             cd->resid, M_WAITOK);
  658                 else
  659                         cd->mpending = NULL;
  660                 if (cd->mreq)
  661                         m_last(cd->mreq)->m_next = m;
  662                 else
  663                         cd->mreq = m;
  664                 while (m) {
  665                         cd->resid -= m->m_len;
  666                         m = m->m_next;
  667                 }
  668         }
  669 
  670         /*
  671          * Block receive upcalls if we have more data pending,
  672          * otherwise report our need.
  673          */
  674         if (cd->mpending)
  675                 so->so_rcv.sb_lowat = INT_MAX;
  676         else
  677                 so->so_rcv.sb_lowat =
  678                     imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2));
  679         return (TRUE);
  680 }
  681 
  682 static bool_t
  683 svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
  684     struct sockaddr **addrp, struct mbuf **mp)
  685 {
  686         struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
  687         struct uio uio;
  688         struct mbuf *m, *ctrl;
  689         struct socket* so = xprt->xp_socket;
  690         XDR xdrs;
  691         int error, rcvflag;
  692         uint32_t reterr, xid_plus_direction[2];
  693         struct cmsghdr *cmsg;
  694         struct tls_get_record tgr;
  695         enum clnt_stat ret;
  696 
  697         /*
  698          * Serialise access to the socket and our own record parsing
  699          * state.
  700          */
  701         sx_xlock(&xprt->xp_lock);
  702 
  703         for (;;) {
  704                 /* If we have no request ready, check pending queue. */
  705                 while (cd->mpending &&
  706                     (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) {
  707                         if (!svc_vc_process_pending(xprt))
  708                                 break;
  709                 }
  710 
  711                 /* Process and return complete request in cd->mreq. */
  712                 if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
  713 
  714                         /*
  715                          * Now, check for a backchannel reply.
  716                          * The XID is in the first uint32_t of the reply
  717                          * and the message direction is the second one.
  718                          */
  719                         if ((cd->mreq->m_len >= sizeof(xid_plus_direction) ||
  720                             m_length(cd->mreq, NULL) >=
  721                             sizeof(xid_plus_direction)) &&
  722                             xprt->xp_p2 != NULL) {
  723                                 m_copydata(cd->mreq, 0,
  724                                     sizeof(xid_plus_direction),
  725                                     (char *)xid_plus_direction);
  726                                 xid_plus_direction[0] =
  727                                     ntohl(xid_plus_direction[0]);
  728                                 xid_plus_direction[1] =
  729                                     ntohl(xid_plus_direction[1]);
  730                                 /* Check message direction. */
  731                                 if (xid_plus_direction[1] == REPLY) {
  732                                         clnt_bck_svccall(xprt->xp_p2,
  733                                             cd->mreq,
  734                                             xid_plus_direction[0]);
  735                                         cd->mreq = NULL;
  736                                         continue;
  737                                 }
  738                         }
  739 
  740                         xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
  741                         cd->mreq = NULL;
  742 
  743                         /* Check for next request in a pending queue. */
  744                         svc_vc_process_pending(xprt);
  745                         if (cd->mreq == NULL || cd->resid != 0) {
  746                                 SOCKBUF_LOCK(&so->so_rcv);
  747                                 if (!soreadable(so))
  748                                         xprt_inactive_self(xprt);
  749                                 SOCKBUF_UNLOCK(&so->so_rcv);
  750                         }
  751 
  752                         sx_xunlock(&xprt->xp_lock);
  753 
  754                         if (! xdr_callmsg(&xdrs, msg)) {
  755                                 XDR_DESTROY(&xdrs);
  756                                 return (FALSE);
  757                         }
  758 
  759                         *addrp = NULL;
  760                         *mp = xdrmbuf_getall(&xdrs);
  761                         XDR_DESTROY(&xdrs);
  762 
  763                         return (TRUE);
  764                 }
  765 
  766                 /*
  767                  * If receiving is disabled so that a TLS handshake can be
  768                  * done by the rpctlssd daemon, return FALSE here.
  769                  */
  770                 rcvflag = MSG_DONTWAIT;
  771                 if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0)
  772                         rcvflag |= MSG_TLSAPPDATA;
  773 tryagain:
  774                 if (xprt->xp_dontrcv) {
  775                         sx_xunlock(&xprt->xp_lock);
  776                         return (FALSE);
  777                 }
  778 
  779                 /*
  780                  * The socket upcall calls xprt_active() which will eventually
  781                  * cause the server to call us here. We attempt to
  782                  * read as much as possible from the socket and put
  783                  * the result in cd->mpending. If the read fails,
  784                  * we have drained both cd->mpending and the socket so
  785                  * we can call xprt_inactive().
  786                  */
  787                 uio.uio_resid = 1000000000;
  788                 uio.uio_td = curthread;
  789                 ctrl = m = NULL;
  790                 error = soreceive(so, NULL, &uio, &m, &ctrl, &rcvflag);
  791 
  792                 if (error == EWOULDBLOCK) {
  793                         /*
  794                          * We must re-test for readability after
  795                          * taking the lock to protect us in the case
  796                          * where a new packet arrives on the socket
  797                          * after our call to soreceive fails with
  798                          * EWOULDBLOCK.
  799                          */
  800                         SOCKBUF_LOCK(&so->so_rcv);
  801                         if (!soreadable(so))
  802                                 xprt_inactive_self(xprt);
  803                         SOCKBUF_UNLOCK(&so->so_rcv);
  804                         sx_xunlock(&xprt->xp_lock);
  805                         return (FALSE);
  806                 }
  807 
  808                 /*
  809                  * A return of ENXIO indicates that there is a
  810                  * non-application data record at the head of the
  811                  * socket's receive queue, for TLS connections.
  812                  * This record needs to be handled in userland
  813                  * via an SSL_read() call, so do an upcall to the daemon.
  814                  */
  815                 if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0 &&
  816                     error == ENXIO) {
  817                         /* Disable reception. */
  818                         xprt->xp_dontrcv = TRUE;
  819                         sx_xunlock(&xprt->xp_lock);
  820                         ret = rpctls_srv_handlerecord(xprt->xp_sslsec,
  821                             xprt->xp_sslusec, xprt->xp_sslrefno,
  822                             &reterr);
  823                         sx_xlock(&xprt->xp_lock);
  824                         xprt->xp_dontrcv = FALSE;
  825                         if (ret != RPC_SUCCESS || reterr != RPCTLSERR_OK) {
  826                                 /*
  827                                  * All we can do is soreceive() it and
  828                                  * then toss it.
  829                                  */
  830                                 rcvflag = MSG_DONTWAIT;
  831                                 goto tryagain;
  832                         }
  833                         sx_xunlock(&xprt->xp_lock);
  834                         xprt_active(xprt);   /* Harmless if already active. */
  835                         return (FALSE);
  836                 }
  837 
  838                 if (error) {
  839                         SOCKBUF_LOCK(&so->so_rcv);
  840                         if (xprt->xp_upcallset) {
  841                                 xprt->xp_upcallset = 0;
  842                                 soupcall_clear(so, SO_RCV);
  843                         }
  844                         SOCKBUF_UNLOCK(&so->so_rcv);
  845                         xprt_inactive_self(xprt);
  846                         cd->strm_stat = XPRT_DIED;
  847                         sx_xunlock(&xprt->xp_lock);
  848                         return (FALSE);
  849                 }
  850 
  851                 if (!m) {
  852                         /*
  853                          * EOF - the other end has closed the socket.
  854                          */
  855                         xprt_inactive_self(xprt);
  856                         cd->strm_stat = XPRT_DIED;
  857                         sx_xunlock(&xprt->xp_lock);
  858                         return (FALSE);
  859                 }
  860 
  861                 /* Process any record header(s). */
  862                 if (ctrl != NULL) {
  863                         cmsg = mtod(ctrl, struct cmsghdr *);
  864                         if (cmsg->cmsg_type == TLS_GET_RECORD &&
  865                             cmsg->cmsg_len == CMSG_LEN(sizeof(tgr))) {
  866                                 memcpy(&tgr, CMSG_DATA(cmsg), sizeof(tgr));
  867                                 /*
  868                                  * This should have been handled by
  869                                  * the rpctls_svc_handlerecord()
  870                                  * upcall.  If not, all we can do is
  871                                  * toss it away.
  872                                  */
  873                                 if (tgr.tls_type != TLS_RLTYPE_APP) {
  874                                         m_freem(m);
  875                                         m_free(ctrl);
  876                                         rcvflag = MSG_DONTWAIT | MSG_TLSAPPDATA;
  877                                         goto tryagain;
  878                                 }
  879                         }
  880                         m_free(ctrl);
  881                 }
  882 
  883                 if (cd->mpending)
  884                         m_last(cd->mpending)->m_next = m;
  885                 else
  886                         cd->mpending = m;
  887         }
  888 }
  889 
  890 static bool_t
  891 svc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
  892     struct sockaddr **addrp, struct mbuf **mp)
  893 {
  894         struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
  895         struct ct_data *ct;
  896         struct mbuf *m;
  897         XDR xdrs;
  898 
  899         sx_xlock(&xprt->xp_lock);
  900         ct = (struct ct_data *)xprt->xp_p2;
  901         if (ct == NULL) {
  902                 sx_xunlock(&xprt->xp_lock);
  903                 return (FALSE);
  904         }
  905         mtx_lock(&ct->ct_lock);
  906         m = cd->mreq;
  907         if (m == NULL) {
  908                 xprt_inactive_self(xprt);
  909                 mtx_unlock(&ct->ct_lock);
  910                 sx_xunlock(&xprt->xp_lock);
  911                 return (FALSE);
  912         }
  913         cd->mreq = m->m_nextpkt;
  914         mtx_unlock(&ct->ct_lock);
  915         sx_xunlock(&xprt->xp_lock);
  916 
  917         xdrmbuf_create(&xdrs, m, XDR_DECODE);
  918         if (! xdr_callmsg(&xdrs, msg)) {
  919                 XDR_DESTROY(&xdrs);
  920                 return (FALSE);
  921         }
  922         *addrp = NULL;
  923         *mp = xdrmbuf_getall(&xdrs);
  924         XDR_DESTROY(&xdrs);
  925         return (TRUE);
  926 }
  927 
  928 static bool_t
  929 svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
  930     struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
  931 {
  932         XDR xdrs;
  933         struct mbuf *mrep;
  934         bool_t stat = TRUE;
  935         int error, len, maxextsiz;
  936 #ifdef KERN_TLS
  937         u_int maxlen;
  938 #endif
  939 
  940         /*
  941          * Leave space for record mark.
  942          */
  943         mrep = m_gethdr(M_WAITOK, MT_DATA);
  944         mrep->m_data += sizeof(uint32_t);
  945 
  946         xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
  947 
  948         if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
  949             msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
  950                 if (!xdr_replymsg(&xdrs, msg))
  951                         stat = FALSE;
  952                 else
  953                         xdrmbuf_append(&xdrs, m);
  954         } else {
  955                 stat = xdr_replymsg(&xdrs, msg);
  956         }
  957 
  958         if (stat) {
  959                 m_fixhdr(mrep);
  960 
  961                 /*
  962                  * Prepend a record marker containing the reply length.
  963                  */
  964                 M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
  965                 len = mrep->m_pkthdr.len;
  966                 *mtod(mrep, uint32_t *) =
  967                         htonl(0x80000000 | (len - sizeof(uint32_t)));
  968 
  969                 /* For RPC-over-TLS, copy mrep to a chain of ext_pgs. */
  970                 if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
  971                         /*
  972                          * Copy the mbuf chain to a chain of
  973                          * ext_pgs mbuf(s) as required by KERN_TLS.
  974                          */
  975                         maxextsiz = TLS_MAX_MSG_SIZE_V10_2;
  976 #ifdef KERN_TLS
  977                         if (rpctls_getinfo(&maxlen, false, false))
  978                                 maxextsiz = min(maxextsiz, maxlen);
  979 #endif
  980                         mrep = _rpc_copym_into_ext_pgs(mrep, maxextsiz);
  981                 }
  982                 atomic_add_32(&xprt->xp_snd_cnt, len);
  983                 /*
  984                  * sosend consumes mreq.
  985                  */
  986                 error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
  987                     0, curthread);
  988                 if (!error) {
  989                         atomic_add_rel_32(&xprt->xp_snt_cnt, len);
  990                         if (seq)
  991                                 *seq = xprt->xp_snd_cnt;
  992                         stat = TRUE;
  993                 } else
  994                         atomic_subtract_32(&xprt->xp_snd_cnt, len);
  995         } else {
  996                 m_freem(mrep);
  997         }
  998 
  999         XDR_DESTROY(&xdrs);
 1000 
 1001         return (stat);
 1002 }
 1003 
 1004 static bool_t
 1005 svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
 1006     struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
 1007 {
 1008         struct ct_data *ct;
 1009         XDR xdrs;
 1010         struct mbuf *mrep;
 1011         bool_t stat = TRUE;
 1012         int error, maxextsiz;
 1013 #ifdef KERN_TLS
 1014         u_int maxlen;
 1015 #endif
 1016 
 1017         /*
 1018          * Leave space for record mark.
 1019          */
 1020         mrep = m_gethdr(M_WAITOK, MT_DATA);
 1021         mrep->m_data += sizeof(uint32_t);
 1022 
 1023         xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
 1024 
 1025         if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
 1026             msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
 1027                 if (!xdr_replymsg(&xdrs, msg))
 1028                         stat = FALSE;
 1029                 else
 1030                         xdrmbuf_append(&xdrs, m);
 1031         } else {
 1032                 stat = xdr_replymsg(&xdrs, msg);
 1033         }
 1034 
 1035         if (stat) {
 1036                 m_fixhdr(mrep);
 1037 
 1038                 /*
 1039                  * Prepend a record marker containing the reply length.
 1040                  */
 1041                 M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
 1042                 *mtod(mrep, uint32_t *) =
 1043                         htonl(0x80000000 | (mrep->m_pkthdr.len
 1044                                 - sizeof(uint32_t)));
 1045 
 1046                 /* For RPC-over-TLS, copy mrep to a chain of ext_pgs. */
 1047                 if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
 1048                         /*
 1049                          * Copy the mbuf chain to a chain of
 1050                          * ext_pgs mbuf(s) as required by KERN_TLS.
 1051                          */
 1052                         maxextsiz = TLS_MAX_MSG_SIZE_V10_2;
 1053 #ifdef KERN_TLS
 1054                         if (rpctls_getinfo(&maxlen, false, false))
 1055                                 maxextsiz = min(maxextsiz, maxlen);
 1056 #endif
 1057                         mrep = _rpc_copym_into_ext_pgs(mrep, maxextsiz);
 1058                 }
 1059                 sx_xlock(&xprt->xp_lock);
 1060                 ct = (struct ct_data *)xprt->xp_p2;
 1061                 if (ct != NULL)
 1062                         error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
 1063                             0, curthread);
 1064                 else
 1065                         error = EPIPE;
 1066                 sx_xunlock(&xprt->xp_lock);
 1067                 if (!error) {
 1068                         stat = TRUE;
 1069                 }
 1070         } else {
 1071                 m_freem(mrep);
 1072         }
 1073 
 1074         XDR_DESTROY(&xdrs);
 1075 
 1076         return (stat);
 1077 }
 1078 
 1079 static bool_t
 1080 svc_vc_null()
 1081 {
 1082 
 1083         return (FALSE);
 1084 }
 1085 
 1086 static int
 1087 svc_vc_soupcall(struct socket *so, void *arg, int waitflag)
 1088 {
 1089         SVCXPRT *xprt = (SVCXPRT *) arg;
 1090 
 1091         if (soreadable(xprt->xp_socket))
 1092                 xprt_active(xprt);
 1093         return (SU_OK);
 1094 }
 1095 
 1096 static int
 1097 svc_vc_rendezvous_soupcall(struct socket *head, void *arg, int waitflag)
 1098 {
 1099         SVCXPRT *xprt = (SVCXPRT *) arg;
 1100 
 1101         if (!TAILQ_EMPTY(&head->sol_comp))
 1102                 xprt_active(xprt);
 1103         return (SU_OK);
 1104 }
 1105 
 1106 #if 0
 1107 /*
 1108  * Get the effective UID of the sending process. Used by rpcbind, keyserv
 1109  * and rpc.yppasswdd on AF_LOCAL.
 1110  */
 1111 int
 1112 __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
 1113         int sock, ret;
 1114         gid_t egid;
 1115         uid_t euid;
 1116         struct sockaddr *sa;
 1117 
 1118         sock = transp->xp_fd;
 1119         sa = (struct sockaddr *)transp->xp_rtaddr;
 1120         if (sa->sa_family == AF_LOCAL) {
 1121                 ret = getpeereid(sock, &euid, &egid);
 1122                 if (ret == 0)
 1123                         *uid = euid;
 1124                 return (ret);
 1125         } else
 1126                 return (-1);
 1127 }
 1128 #endif

Cache object: 0feb34c33fa69610573133f7402551d7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.