1177633Sdfr/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2177633Sdfr 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 6261046Smav * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 17177633Sdfr * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * 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: stable/10/sys/rpc/svc_vc.c 309503 2016-12-03 19:03:25Z ngie $"); 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> 47177633Sdfr#include <sys/lock.h> 48177633Sdfr#include <sys/kernel.h> 49177633Sdfr#include <sys/malloc.h> 50177633Sdfr#include <sys/mbuf.h> 51177633Sdfr#include <sys/mutex.h> 52193509Srwatson#include <sys/proc.h> 53177633Sdfr#include <sys/protosw.h> 54177633Sdfr#include <sys/queue.h> 55177633Sdfr#include <sys/socket.h> 56177633Sdfr#include <sys/socketvar.h> 57184588Sdfr#include <sys/sx.h> 58177633Sdfr#include <sys/systm.h> 59177633Sdfr#include <sys/uio.h> 60196503Szec 61196503Szec#include <net/vnet.h> 62196503Szec 63177633Sdfr#include <netinet/tcp.h> 64177633Sdfr 65177633Sdfr#include <rpc/rpc.h> 66177633Sdfr 67244008Srmacklem#include <rpc/krpc.h> 68177685Sdfr#include <rpc/rpc_com.h> 69177633Sdfr 70193509Srwatson#include <security/mac/mac_framework.h> 71193509Srwatson 72184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 73184588Sdfr struct sockaddr **, struct mbuf **); 74177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 75177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *); 76177633Sdfrstatic bool_t svc_vc_null(void); 77177633Sdfrstatic void svc_vc_destroy(SVCXPRT *); 78177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 79261055Smavstatic bool_t svc_vc_ack(SVCXPRT *, uint32_t *); 80184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *, 81184588Sdfr struct sockaddr **, struct mbuf **); 82184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *, 83261055Smav struct sockaddr *, struct mbuf *, uint32_t *seq); 84177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 85177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 86177633Sdfr void *in); 87244008Srmacklemstatic void svc_vc_backchannel_destroy(SVCXPRT *); 88244008Srmacklemstatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *); 89244008Srmacklemstatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *, 90244008Srmacklem struct sockaddr **, struct mbuf **); 91244008Srmacklemstatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *, 92261055Smav struct sockaddr *, struct mbuf *, uint32_t *); 93244008Srmacklemstatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, 94244008Srmacklem void *in); 95177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so, 96177633Sdfr struct sockaddr *raddr); 97177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop); 98193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag); 99177633Sdfr 100177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = { 101177633Sdfr .xp_recv = svc_vc_rendezvous_recv, 102177633Sdfr .xp_stat = svc_vc_rendezvous_stat, 103184588Sdfr .xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *, 104261055Smav struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null, 105177633Sdfr .xp_destroy = svc_vc_rendezvous_destroy, 106177633Sdfr .xp_control = svc_vc_rendezvous_control 107177633Sdfr}; 108177633Sdfr 109177633Sdfrstatic struct xp_ops svc_vc_ops = { 110177633Sdfr .xp_recv = svc_vc_recv, 111177633Sdfr .xp_stat = svc_vc_stat, 112261055Smav .xp_ack = svc_vc_ack, 113177633Sdfr .xp_reply = svc_vc_reply, 114177633Sdfr .xp_destroy = svc_vc_destroy, 115177633Sdfr .xp_control = svc_vc_control 116177633Sdfr}; 117177633Sdfr 118244008Srmacklemstatic struct xp_ops svc_vc_backchannel_ops = { 119244008Srmacklem .xp_recv = svc_vc_backchannel_recv, 120244008Srmacklem .xp_stat = svc_vc_backchannel_stat, 121244008Srmacklem .xp_reply = svc_vc_backchannel_reply, 122244008Srmacklem .xp_destroy = svc_vc_backchannel_destroy, 123244008Srmacklem .xp_control = svc_vc_backchannel_control 124177633Sdfr}; 125177633Sdfr 126177633Sdfr/* 127177633Sdfr * Usage: 128177633Sdfr * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 129177633Sdfr * 130177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter. 131177633Sdfr * Once *xprt is initialized, it is registered as a transporter 132177633Sdfr * see (svc.h, xprt_register). This routine returns 133177633Sdfr * a NULL if a problem occurred. 134177633Sdfr * 135177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but 136177633Sdfr * not yet connected socket. 137177633Sdfr * 138177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify 139177633Sdfr * how big the send and receive buffers are via the second and third parms; 140177633Sdfr * 0 => use the system default. 141177633Sdfr */ 142177633SdfrSVCXPRT * 143177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 144177633Sdfr size_t recvsize) 145177633Sdfr{ 146177633Sdfr SVCXPRT *xprt; 147177633Sdfr struct sockaddr* sa; 148177633Sdfr int error; 149177633Sdfr 150249263Sjhb SOCK_LOCK(so); 151249263Sjhb if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) { 152249263Sjhb SOCK_UNLOCK(so); 153287338Sdelphij CURVNET_SET(so->so_vnet); 154180025Sdfr error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 155287338Sdelphij CURVNET_RESTORE(); 156180025Sdfr if (error) 157180025Sdfr return (NULL); 158180025Sdfr xprt = svc_vc_create_conn(pool, so, sa); 159180025Sdfr free(sa, M_SONAME); 160180025Sdfr return (xprt); 161180025Sdfr } 162249263Sjhb SOCK_UNLOCK(so); 163180025Sdfr 164184588Sdfr xprt = svc_xprt_alloc(); 165184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 166177633Sdfr xprt->xp_pool = pool; 167177633Sdfr xprt->xp_socket = so; 168177633Sdfr xprt->xp_p1 = NULL; 169177633Sdfr xprt->xp_p2 = NULL; 170177633Sdfr xprt->xp_ops = &svc_vc_rendezvous_ops; 171177633Sdfr 172287338Sdelphij CURVNET_SET(so->so_vnet); 173177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 174287338Sdelphij CURVNET_RESTORE(); 175196503Szec if (error) { 176177633Sdfr goto cleanup_svc_vc_create; 177196503Szec } 178177633Sdfr 179184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 180177633Sdfr free(sa, M_SONAME); 181177633Sdfr 182177633Sdfr xprt_register(xprt); 183177633Sdfr 184281520Smav solisten(so, -1, curthread); 185177633Sdfr 186177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 187193436Srmacklem xprt->xp_upcallset = 1; 188193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 189177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 190177633Sdfr 191177633Sdfr return (xprt); 192301801Sngie 193177633Sdfrcleanup_svc_vc_create: 194301801Sngie sx_destroy(&xprt->xp_lock); 195301801Sngie svc_xprt_free(xprt); 196301801Sngie 197177633Sdfr return (NULL); 198177633Sdfr} 199177633Sdfr 200177633Sdfr/* 201177633Sdfr * Create a new transport for a socket optained via soaccept(). 202177633Sdfr */ 203177633SdfrSVCXPRT * 204177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 205177633Sdfr{ 206301801Sngie SVCXPRT *xprt; 207301801Sngie struct cf_conn *cd; 208177633Sdfr struct sockaddr* sa = NULL; 209180025Sdfr struct sockopt opt; 210180025Sdfr int one = 1; 211177633Sdfr int error; 212177633Sdfr 213180025Sdfr bzero(&opt, sizeof(struct sockopt)); 214180025Sdfr opt.sopt_dir = SOPT_SET; 215180025Sdfr opt.sopt_level = SOL_SOCKET; 216180025Sdfr opt.sopt_name = SO_KEEPALIVE; 217180025Sdfr opt.sopt_val = &one; 218180025Sdfr opt.sopt_valsize = sizeof(one); 219180025Sdfr error = sosetopt(so, &opt); 220196503Szec if (error) { 221180025Sdfr return (NULL); 222196503Szec } 223180025Sdfr 224180025Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 225180025Sdfr bzero(&opt, sizeof(struct sockopt)); 226180025Sdfr opt.sopt_dir = SOPT_SET; 227180025Sdfr opt.sopt_level = IPPROTO_TCP; 228180025Sdfr opt.sopt_name = TCP_NODELAY; 229180025Sdfr opt.sopt_val = &one; 230180025Sdfr opt.sopt_valsize = sizeof(one); 231180025Sdfr error = sosetopt(so, &opt); 232196503Szec if (error) { 233180025Sdfr return (NULL); 234196503Szec } 235180025Sdfr } 236180025Sdfr 237177633Sdfr cd = mem_alloc(sizeof(*cd)); 238177633Sdfr cd->strm_stat = XPRT_IDLE; 239177633Sdfr 240184588Sdfr xprt = svc_xprt_alloc(); 241184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 242177633Sdfr xprt->xp_pool = pool; 243177633Sdfr xprt->xp_socket = so; 244177633Sdfr xprt->xp_p1 = cd; 245177633Sdfr xprt->xp_p2 = NULL; 246177633Sdfr xprt->xp_ops = &svc_vc_ops; 247177633Sdfr 248184588Sdfr /* 249184588Sdfr * See http://www.connectathon.org/talks96/nfstcp.pdf - client 250184588Sdfr * has a 5 minute timer, server has a 6 minute timer. 251184588Sdfr */ 252184588Sdfr xprt->xp_idletimeout = 6 * 60; 253177633Sdfr 254184588Sdfr memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 255184588Sdfr 256287338Sdelphij CURVNET_SET(so->so_vnet); 257177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 258287338Sdelphij CURVNET_RESTORE(); 259177633Sdfr if (error) 260177633Sdfr goto cleanup_svc_vc_create; 261177633Sdfr 262184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 263177633Sdfr free(sa, M_SONAME); 264177633Sdfr 265177633Sdfr xprt_register(xprt); 266177633Sdfr 267177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 268193436Srmacklem xprt->xp_upcallset = 1; 269193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 270177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 271177633Sdfr 272177633Sdfr /* 273177633Sdfr * Throw the transport into the active list in case it already 274177633Sdfr * has some data buffered. 275177633Sdfr */ 276184588Sdfr sx_xlock(&xprt->xp_lock); 277177633Sdfr xprt_active(xprt); 278184588Sdfr sx_xunlock(&xprt->xp_lock); 279177633Sdfr 280177633Sdfr return (xprt); 281177633Sdfrcleanup_svc_vc_create: 282301801Sngie sx_destroy(&xprt->xp_lock); 283301801Sngie svc_xprt_free(xprt); 284301801Sngie mem_free(cd, sizeof(*cd)); 285301801Sngie 286177633Sdfr return (NULL); 287177633Sdfr} 288177633Sdfr 289177633Sdfr/* 290244008Srmacklem * Create a new transport for a backchannel on a clnt_vc socket. 291244008Srmacklem */ 292244008SrmacklemSVCXPRT * 293244008Srmacklemsvc_vc_create_backchannel(SVCPOOL *pool) 294244008Srmacklem{ 295244008Srmacklem SVCXPRT *xprt = NULL; 296244008Srmacklem struct cf_conn *cd = NULL; 297244008Srmacklem 298244008Srmacklem cd = mem_alloc(sizeof(*cd)); 299244008Srmacklem cd->strm_stat = XPRT_IDLE; 300244008Srmacklem 301244008Srmacklem xprt = svc_xprt_alloc(); 302244008Srmacklem sx_init(&xprt->xp_lock, "xprt->xp_lock"); 303244008Srmacklem xprt->xp_pool = pool; 304244008Srmacklem xprt->xp_socket = NULL; 305244008Srmacklem xprt->xp_p1 = cd; 306244008Srmacklem xprt->xp_p2 = NULL; 307244008Srmacklem xprt->xp_ops = &svc_vc_backchannel_ops; 308244008Srmacklem return (xprt); 309244008Srmacklem} 310244008Srmacklem 311244008Srmacklem/* 312177633Sdfr * This does all of the accept except the final call to soaccept. The 313177633Sdfr * caller will call soaccept after dropping its locks (soaccept may 314177633Sdfr * call malloc). 315177633Sdfr */ 316177633Sdfrint 317177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop) 318177633Sdfr{ 319177633Sdfr int error = 0; 320177633Sdfr struct socket *so; 321177633Sdfr 322177633Sdfr if ((head->so_options & SO_ACCEPTCONN) == 0) { 323177633Sdfr error = EINVAL; 324177633Sdfr goto done; 325177633Sdfr } 326177633Sdfr#ifdef MAC 327193509Srwatson error = mac_socket_check_accept(curthread->td_ucred, head); 328177633Sdfr if (error != 0) 329177633Sdfr goto done; 330177633Sdfr#endif 331177633Sdfr ACCEPT_LOCK(); 332177633Sdfr if (TAILQ_EMPTY(&head->so_comp)) { 333177633Sdfr ACCEPT_UNLOCK(); 334177633Sdfr error = EWOULDBLOCK; 335177633Sdfr goto done; 336177633Sdfr } 337177633Sdfr so = TAILQ_FIRST(&head->so_comp); 338177633Sdfr KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 339177633Sdfr KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 340177633Sdfr 341177633Sdfr /* 342177633Sdfr * Before changing the flags on the socket, we have to bump the 343177633Sdfr * reference count. Otherwise, if the protocol calls sofree(), 344177633Sdfr * the socket will be released due to a zero refcount. 345177633Sdfr * XXX might not need soref() since this is simpler than kern_accept. 346177633Sdfr */ 347177633Sdfr SOCK_LOCK(so); /* soref() and so_state update */ 348177633Sdfr soref(so); /* file descriptor reference */ 349177633Sdfr 350177633Sdfr TAILQ_REMOVE(&head->so_comp, so, so_list); 351177633Sdfr head->so_qlen--; 352177633Sdfr so->so_state |= (head->so_state & SS_NBIO); 353177633Sdfr so->so_qstate &= ~SQ_COMP; 354177633Sdfr so->so_head = NULL; 355177633Sdfr 356177633Sdfr SOCK_UNLOCK(so); 357177633Sdfr ACCEPT_UNLOCK(); 358177633Sdfr 359177633Sdfr *sop = so; 360177633Sdfr 361177633Sdfr /* connection has been removed from the listen queue */ 362177633Sdfr KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 363177633Sdfrdone: 364177633Sdfr return (error); 365177633Sdfr} 366177633Sdfr 367177633Sdfr/*ARGSUSED*/ 368177633Sdfrstatic bool_t 369184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 370184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 371177633Sdfr{ 372177633Sdfr struct socket *so = NULL; 373177633Sdfr struct sockaddr *sa = NULL; 374177633Sdfr int error; 375194407Srmacklem SVCXPRT *new_xprt; 376177633Sdfr 377177633Sdfr /* 378177633Sdfr * The socket upcall calls xprt_active() which will eventually 379177633Sdfr * cause the server to call us here. We attempt to accept a 380177633Sdfr * connection from the socket and turn it into a new 381177633Sdfr * transport. If the accept fails, we have drained all pending 382177633Sdfr * connections so we call xprt_inactive(). 383177633Sdfr */ 384184588Sdfr sx_xlock(&xprt->xp_lock); 385177633Sdfr 386177633Sdfr error = svc_vc_accept(xprt->xp_socket, &so); 387177633Sdfr 388177633Sdfr if (error == EWOULDBLOCK) { 389184588Sdfr /* 390184588Sdfr * We must re-test for new connections after taking 391184588Sdfr * the lock to protect us in the case where a new 392184588Sdfr * connection arrives after our call to accept fails 393261047Smav * with EWOULDBLOCK. 394184588Sdfr */ 395184588Sdfr ACCEPT_LOCK(); 396184588Sdfr if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 397261053Smav xprt_inactive_self(xprt); 398184588Sdfr ACCEPT_UNLOCK(); 399184588Sdfr sx_xunlock(&xprt->xp_lock); 400177633Sdfr return (FALSE); 401177633Sdfr } 402177633Sdfr 403177633Sdfr if (error) { 404177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 405193436Srmacklem if (xprt->xp_upcallset) { 406193436Srmacklem xprt->xp_upcallset = 0; 407193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 408193436Srmacklem } 409177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 410261053Smav xprt_inactive_self(xprt); 411184588Sdfr sx_xunlock(&xprt->xp_lock); 412177633Sdfr return (FALSE); 413177633Sdfr } 414177633Sdfr 415184588Sdfr sx_xunlock(&xprt->xp_lock); 416177633Sdfr 417309503Sngie sa = NULL; 418177633Sdfr error = soaccept(so, &sa); 419177633Sdfr 420177633Sdfr if (error) { 421177633Sdfr /* 422177633Sdfr * XXX not sure if I need to call sofree or soclose here. 423177633Sdfr */ 424177633Sdfr if (sa) 425177633Sdfr free(sa, M_SONAME); 426177633Sdfr return (FALSE); 427177633Sdfr } 428177633Sdfr 429177633Sdfr /* 430177633Sdfr * svc_vc_create_conn will call xprt_register - we don't need 431194407Srmacklem * to do anything with the new connection except derefence it. 432177633Sdfr */ 433194407Srmacklem new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 434194407Srmacklem if (!new_xprt) { 435180025Sdfr soclose(so); 436194407Srmacklem } else { 437194407Srmacklem SVC_RELEASE(new_xprt); 438194407Srmacklem } 439180025Sdfr 440177633Sdfr free(sa, M_SONAME); 441177633Sdfr 442177633Sdfr return (FALSE); /* there is never an rpc msg to be processed */ 443177633Sdfr} 444177633Sdfr 445177633Sdfr/*ARGSUSED*/ 446177633Sdfrstatic enum xprt_stat 447177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt) 448177633Sdfr{ 449177633Sdfr 450177633Sdfr return (XPRT_IDLE); 451177633Sdfr} 452177633Sdfr 453177633Sdfrstatic void 454177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt) 455177633Sdfr{ 456177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 457193436Srmacklem if (xprt->xp_upcallset) { 458193436Srmacklem xprt->xp_upcallset = 0; 459193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 460193436Srmacklem } 461177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 462177633Sdfr 463177633Sdfr if (xprt->xp_socket) 464177633Sdfr (void)soclose(xprt->xp_socket); 465177633Sdfr 466184588Sdfr if (xprt->xp_netid) 467184588Sdfr (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 468184588Sdfr svc_xprt_free(xprt); 469177633Sdfr} 470177633Sdfr 471177633Sdfrstatic void 472177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 473177633Sdfr{ 474177633Sdfr 475177633Sdfr svc_vc_destroy_common(xprt); 476177633Sdfr} 477177633Sdfr 478177633Sdfrstatic void 479177633Sdfrsvc_vc_destroy(SVCXPRT *xprt) 480177633Sdfr{ 481177633Sdfr struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 482177633Sdfr 483177633Sdfr svc_vc_destroy_common(xprt); 484177633Sdfr 485177633Sdfr if (cd->mreq) 486177633Sdfr m_freem(cd->mreq); 487177633Sdfr if (cd->mpending) 488177633Sdfr m_freem(cd->mpending); 489177633Sdfr mem_free(cd, sizeof(*cd)); 490177633Sdfr} 491177633Sdfr 492244008Srmacklemstatic void 493244008Srmacklemsvc_vc_backchannel_destroy(SVCXPRT *xprt) 494244008Srmacklem{ 495244008Srmacklem struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 496244008Srmacklem struct mbuf *m, *m2; 497244008Srmacklem 498244008Srmacklem svc_xprt_free(xprt); 499244008Srmacklem m = cd->mreq; 500244008Srmacklem while (m != NULL) { 501244008Srmacklem m2 = m; 502244008Srmacklem m = m->m_nextpkt; 503244008Srmacklem m_freem(m2); 504244008Srmacklem } 505244008Srmacklem mem_free(cd, sizeof(*cd)); 506244008Srmacklem} 507244008Srmacklem 508177633Sdfr/*ARGSUSED*/ 509177633Sdfrstatic bool_t 510177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 511177633Sdfr{ 512177633Sdfr return (FALSE); 513177633Sdfr} 514177633Sdfr 515177633Sdfrstatic bool_t 516177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 517177633Sdfr{ 518177633Sdfr 519177633Sdfr return (FALSE); 520177633Sdfr} 521177633Sdfr 522244008Srmacklemstatic bool_t 523244008Srmacklemsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 524244008Srmacklem{ 525244008Srmacklem 526244008Srmacklem return (FALSE); 527244008Srmacklem} 528244008Srmacklem 529177633Sdfrstatic enum xprt_stat 530177633Sdfrsvc_vc_stat(SVCXPRT *xprt) 531177633Sdfr{ 532177633Sdfr struct cf_conn *cd; 533177633Sdfr 534177633Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 535177633Sdfr 536177633Sdfr if (cd->strm_stat == XPRT_DIED) 537177633Sdfr return (XPRT_DIED); 538177633Sdfr 539261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) 540261047Smav return (XPRT_MOREREQS); 541177633Sdfr 542184588Sdfr if (soreadable(xprt->xp_socket)) 543184588Sdfr return (XPRT_MOREREQS); 544184588Sdfr 545177633Sdfr return (XPRT_IDLE); 546177633Sdfr} 547177633Sdfr 548261055Smavstatic bool_t 549261055Smavsvc_vc_ack(SVCXPRT *xprt, uint32_t *ack) 550261055Smav{ 551261055Smav 552261055Smav *ack = atomic_load_acq_32(&xprt->xp_snt_cnt); 553261055Smav *ack -= xprt->xp_socket->so_snd.sb_cc; 554261055Smav return (TRUE); 555261055Smav} 556261055Smav 557244008Srmacklemstatic enum xprt_stat 558244008Srmacklemsvc_vc_backchannel_stat(SVCXPRT *xprt) 559244008Srmacklem{ 560244008Srmacklem struct cf_conn *cd; 561244008Srmacklem 562244008Srmacklem cd = (struct cf_conn *)(xprt->xp_p1); 563244008Srmacklem 564244008Srmacklem if (cd->mreq != NULL) 565244008Srmacklem return (XPRT_MOREREQS); 566244008Srmacklem 567244008Srmacklem return (XPRT_IDLE); 568244008Srmacklem} 569244008Srmacklem 570261047Smav/* 571261047Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it, 572261047Smav * leaving the result in cd->mreq. If we don't have a complete record, leave 573261047Smav * the partial result in cd->mreq and try to read more from the socket. 574261047Smav */ 575261050Smavstatic int 576261047Smavsvc_vc_process_pending(SVCXPRT *xprt) 577261047Smav{ 578261047Smav struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 579261047Smav struct socket *so = xprt->xp_socket; 580261047Smav struct mbuf *m; 581261047Smav 582261047Smav /* 583261047Smav * If cd->resid is non-zero, we have part of the 584261047Smav * record already, otherwise we are expecting a record 585261047Smav * marker. 586261047Smav */ 587261047Smav if (!cd->resid && cd->mpending) { 588261047Smav /* 589261047Smav * See if there is enough data buffered to 590261047Smav * make up a record marker. Make sure we can 591261047Smav * handle the case where the record marker is 592261047Smav * split across more than one mbuf. 593261047Smav */ 594261047Smav size_t n = 0; 595261047Smav uint32_t header; 596261047Smav 597261047Smav m = cd->mpending; 598261047Smav while (n < sizeof(uint32_t) && m) { 599261047Smav n += m->m_len; 600261047Smav m = m->m_next; 601261047Smav } 602261047Smav if (n < sizeof(uint32_t)) { 603261047Smav so->so_rcv.sb_lowat = sizeof(uint32_t) - n; 604261050Smav return (FALSE); 605261047Smav } 606261047Smav m_copydata(cd->mpending, 0, sizeof(header), 607261047Smav (char *)&header); 608261047Smav header = ntohl(header); 609261047Smav cd->eor = (header & 0x80000000) != 0; 610261047Smav cd->resid = header & 0x7fffffff; 611261047Smav m_adj(cd->mpending, sizeof(uint32_t)); 612261047Smav } 613261047Smav 614261047Smav /* 615261047Smav * Start pulling off mbufs from cd->mpending 616261047Smav * until we either have a complete record or 617261047Smav * we run out of data. We use m_split to pull 618261047Smav * data - it will pull as much as possible and 619261047Smav * split the last mbuf if necessary. 620261047Smav */ 621261047Smav while (cd->mpending && cd->resid) { 622261047Smav m = cd->mpending; 623261047Smav if (cd->mpending->m_next 624261047Smav || cd->mpending->m_len > cd->resid) 625261047Smav cd->mpending = m_split(cd->mpending, 626261047Smav cd->resid, M_WAITOK); 627261047Smav else 628261047Smav cd->mpending = NULL; 629261047Smav if (cd->mreq) 630261047Smav m_last(cd->mreq)->m_next = m; 631261047Smav else 632261047Smav cd->mreq = m; 633261047Smav while (m) { 634261047Smav cd->resid -= m->m_len; 635261047Smav m = m->m_next; 636261047Smav } 637261047Smav } 638261047Smav 639261052Smav /* 640261052Smav * Block receive upcalls if we have more data pending, 641261052Smav * otherwise report our need. 642261052Smav */ 643261052Smav if (cd->mpending) 644261052Smav so->so_rcv.sb_lowat = INT_MAX; 645261052Smav else 646261052Smav so->so_rcv.sb_lowat = 647261052Smav imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2)); 648261050Smav return (TRUE); 649261047Smav} 650261047Smav 651177633Sdfrstatic bool_t 652184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 653184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 654177633Sdfr{ 655177633Sdfr struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 656177633Sdfr struct uio uio; 657177633Sdfr struct mbuf *m; 658261047Smav struct socket* so = xprt->xp_socket; 659184588Sdfr XDR xdrs; 660177633Sdfr int error, rcvflag; 661269398Srmacklem uint32_t xid_plus_direction[2]; 662177633Sdfr 663184588Sdfr /* 664184588Sdfr * Serialise access to the socket and our own record parsing 665184588Sdfr * state. 666184588Sdfr */ 667184588Sdfr sx_xlock(&xprt->xp_lock); 668184588Sdfr 669177633Sdfr for (;;) { 670261047Smav /* If we have no request ready, check pending queue. */ 671261047Smav while (cd->mpending && 672261050Smav (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) { 673261050Smav if (!svc_vc_process_pending(xprt)) 674261050Smav break; 675261050Smav } 676177633Sdfr 677261047Smav /* Process and return complete request in cd->mreq. */ 678261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) { 679177633Sdfr 680269398Srmacklem /* 681269398Srmacklem * Now, check for a backchannel reply. 682269398Srmacklem * The XID is in the first uint32_t of the reply 683269398Srmacklem * and the message direction is the second one. 684269398Srmacklem */ 685269398Srmacklem if ((cd->mreq->m_len >= sizeof(xid_plus_direction) || 686269398Srmacklem m_length(cd->mreq, NULL) >= 687269398Srmacklem sizeof(xid_plus_direction)) && 688269398Srmacklem xprt->xp_p2 != NULL) { 689269398Srmacklem m_copydata(cd->mreq, 0, 690269398Srmacklem sizeof(xid_plus_direction), 691269398Srmacklem (char *)xid_plus_direction); 692269398Srmacklem xid_plus_direction[0] = 693269398Srmacklem ntohl(xid_plus_direction[0]); 694269398Srmacklem xid_plus_direction[1] = 695269398Srmacklem ntohl(xid_plus_direction[1]); 696269398Srmacklem /* Check message direction. */ 697269398Srmacklem if (xid_plus_direction[1] == REPLY) { 698269398Srmacklem clnt_bck_svccall(xprt->xp_p2, 699269398Srmacklem cd->mreq, 700269398Srmacklem xid_plus_direction[0]); 701269398Srmacklem cd->mreq = NULL; 702269398Srmacklem continue; 703269398Srmacklem } 704269398Srmacklem } 705269398Srmacklem 706261047Smav xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 707261047Smav cd->mreq = NULL; 708261047Smav 709261047Smav /* Check for next request in a pending queue. */ 710261047Smav svc_vc_process_pending(xprt); 711261047Smav if (cd->mreq == NULL || cd->resid != 0) { 712261047Smav SOCKBUF_LOCK(&so->so_rcv); 713261047Smav if (!soreadable(so)) 714261053Smav xprt_inactive_self(xprt); 715261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 716177633Sdfr } 717177633Sdfr 718261047Smav sx_xunlock(&xprt->xp_lock); 719177633Sdfr 720261047Smav if (! xdr_callmsg(&xdrs, msg)) { 721261047Smav XDR_DESTROY(&xdrs); 722261047Smav return (FALSE); 723261047Smav } 724184588Sdfr 725261047Smav *addrp = NULL; 726261047Smav *mp = xdrmbuf_getall(&xdrs); 727261047Smav XDR_DESTROY(&xdrs); 728177633Sdfr 729261047Smav return (TRUE); 730177633Sdfr } 731177633Sdfr 732177633Sdfr /* 733177633Sdfr * The socket upcall calls xprt_active() which will eventually 734177633Sdfr * cause the server to call us here. We attempt to 735177633Sdfr * read as much as possible from the socket and put 736177633Sdfr * the result in cd->mpending. If the read fails, 737177633Sdfr * we have drained both cd->mpending and the socket so 738177633Sdfr * we can call xprt_inactive(). 739177633Sdfr */ 740177633Sdfr uio.uio_resid = 1000000000; 741177633Sdfr uio.uio_td = curthread; 742177633Sdfr m = NULL; 743177633Sdfr rcvflag = MSG_DONTWAIT; 744261047Smav error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 745177633Sdfr 746177633Sdfr if (error == EWOULDBLOCK) { 747184588Sdfr /* 748184588Sdfr * We must re-test for readability after 749184588Sdfr * taking the lock to protect us in the case 750184588Sdfr * where a new packet arrives on the socket 751184588Sdfr * after our call to soreceive fails with 752261047Smav * EWOULDBLOCK. 753184588Sdfr */ 754261047Smav SOCKBUF_LOCK(&so->so_rcv); 755261047Smav if (!soreadable(so)) 756261053Smav xprt_inactive_self(xprt); 757261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 758184588Sdfr sx_xunlock(&xprt->xp_lock); 759177633Sdfr return (FALSE); 760177633Sdfr } 761177633Sdfr 762177633Sdfr if (error) { 763261047Smav SOCKBUF_LOCK(&so->so_rcv); 764193436Srmacklem if (xprt->xp_upcallset) { 765193436Srmacklem xprt->xp_upcallset = 0; 766261047Smav soupcall_clear(so, SO_RCV); 767193436Srmacklem } 768261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 769261053Smav xprt_inactive_self(xprt); 770177633Sdfr cd->strm_stat = XPRT_DIED; 771184588Sdfr sx_xunlock(&xprt->xp_lock); 772177633Sdfr return (FALSE); 773177633Sdfr } 774177633Sdfr 775177633Sdfr if (!m) { 776177633Sdfr /* 777177633Sdfr * EOF - the other end has closed the socket. 778177633Sdfr */ 779261053Smav xprt_inactive_self(xprt); 780177633Sdfr cd->strm_stat = XPRT_DIED; 781184588Sdfr sx_xunlock(&xprt->xp_lock); 782177633Sdfr return (FALSE); 783177633Sdfr } 784177633Sdfr 785177633Sdfr if (cd->mpending) 786177633Sdfr m_last(cd->mpending)->m_next = m; 787177633Sdfr else 788177633Sdfr cd->mpending = m; 789177633Sdfr } 790177633Sdfr} 791177633Sdfr 792177633Sdfrstatic bool_t 793244008Srmacklemsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 794244008Srmacklem struct sockaddr **addrp, struct mbuf **mp) 795244008Srmacklem{ 796244008Srmacklem struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 797244008Srmacklem struct ct_data *ct; 798244008Srmacklem struct mbuf *m; 799244008Srmacklem XDR xdrs; 800244008Srmacklem 801244008Srmacklem sx_xlock(&xprt->xp_lock); 802244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 803244008Srmacklem if (ct == NULL) { 804244008Srmacklem sx_xunlock(&xprt->xp_lock); 805244008Srmacklem return (FALSE); 806244008Srmacklem } 807244008Srmacklem mtx_lock(&ct->ct_lock); 808244008Srmacklem m = cd->mreq; 809244008Srmacklem if (m == NULL) { 810261053Smav xprt_inactive_self(xprt); 811244008Srmacklem mtx_unlock(&ct->ct_lock); 812244008Srmacklem sx_xunlock(&xprt->xp_lock); 813244008Srmacklem return (FALSE); 814244008Srmacklem } 815244008Srmacklem cd->mreq = m->m_nextpkt; 816244008Srmacklem mtx_unlock(&ct->ct_lock); 817244008Srmacklem sx_xunlock(&xprt->xp_lock); 818244008Srmacklem 819244008Srmacklem xdrmbuf_create(&xdrs, m, XDR_DECODE); 820244008Srmacklem if (! xdr_callmsg(&xdrs, msg)) { 821244008Srmacklem XDR_DESTROY(&xdrs); 822244008Srmacklem return (FALSE); 823244008Srmacklem } 824244008Srmacklem *addrp = NULL; 825244008Srmacklem *mp = xdrmbuf_getall(&xdrs); 826244008Srmacklem XDR_DESTROY(&xdrs); 827244008Srmacklem return (TRUE); 828244008Srmacklem} 829244008Srmacklem 830244008Srmacklemstatic bool_t 831184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 832261055Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 833177633Sdfr{ 834177633Sdfr XDR xdrs; 835177633Sdfr struct mbuf *mrep; 836184588Sdfr bool_t stat = TRUE; 837261055Smav int error, len; 838177633Sdfr 839177633Sdfr /* 840177633Sdfr * Leave space for record mark. 841177633Sdfr */ 842248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 843177633Sdfr mrep->m_data += sizeof(uint32_t); 844177633Sdfr 845184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 846184588Sdfr 847184588Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 848184588Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 849184588Sdfr if (!xdr_replymsg(&xdrs, msg)) 850184588Sdfr stat = FALSE; 851184588Sdfr else 852184588Sdfr xdrmbuf_append(&xdrs, m); 853184588Sdfr } else { 854184588Sdfr stat = xdr_replymsg(&xdrs, msg); 855184588Sdfr } 856184588Sdfr 857184588Sdfr if (stat) { 858177633Sdfr m_fixhdr(mrep); 859177633Sdfr 860177633Sdfr /* 861177633Sdfr * Prepend a record marker containing the reply length. 862177633Sdfr */ 863243882Sglebius M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 864261055Smav len = mrep->m_pkthdr.len; 865177633Sdfr *mtod(mrep, uint32_t *) = 866261055Smav htonl(0x80000000 | (len - sizeof(uint32_t))); 867261055Smav atomic_add_acq_32(&xprt->xp_snd_cnt, len); 868177633Sdfr error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 869177633Sdfr 0, curthread); 870177633Sdfr if (!error) { 871261055Smav atomic_add_rel_32(&xprt->xp_snt_cnt, len); 872261055Smav if (seq) 873261055Smav *seq = xprt->xp_snd_cnt; 874177633Sdfr stat = TRUE; 875261055Smav } else 876261055Smav atomic_subtract_32(&xprt->xp_snd_cnt, len); 877177633Sdfr } else { 878177633Sdfr m_freem(mrep); 879177633Sdfr } 880177633Sdfr 881184588Sdfr XDR_DESTROY(&xdrs); 882177633Sdfr 883177633Sdfr return (stat); 884177633Sdfr} 885177633Sdfr 886177633Sdfrstatic bool_t 887244008Srmacklemsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 888261055Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 889244008Srmacklem{ 890244008Srmacklem struct ct_data *ct; 891244008Srmacklem XDR xdrs; 892244008Srmacklem struct mbuf *mrep; 893244008Srmacklem bool_t stat = TRUE; 894244008Srmacklem int error; 895244008Srmacklem 896244008Srmacklem /* 897244008Srmacklem * Leave space for record mark. 898244008Srmacklem */ 899248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 900244008Srmacklem mrep->m_data += sizeof(uint32_t); 901244008Srmacklem 902244008Srmacklem xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 903244008Srmacklem 904244008Srmacklem if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 905244008Srmacklem msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 906244008Srmacklem if (!xdr_replymsg(&xdrs, msg)) 907244008Srmacklem stat = FALSE; 908244008Srmacklem else 909244008Srmacklem xdrmbuf_append(&xdrs, m); 910244008Srmacklem } else { 911244008Srmacklem stat = xdr_replymsg(&xdrs, msg); 912244008Srmacklem } 913244008Srmacklem 914244008Srmacklem if (stat) { 915244008Srmacklem m_fixhdr(mrep); 916244008Srmacklem 917244008Srmacklem /* 918244008Srmacklem * Prepend a record marker containing the reply length. 919244008Srmacklem */ 920244008Srmacklem M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 921244008Srmacklem *mtod(mrep, uint32_t *) = 922244008Srmacklem htonl(0x80000000 | (mrep->m_pkthdr.len 923244008Srmacklem - sizeof(uint32_t))); 924244008Srmacklem sx_xlock(&xprt->xp_lock); 925244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 926244008Srmacklem if (ct != NULL) 927244008Srmacklem error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 928244008Srmacklem 0, curthread); 929244008Srmacklem else 930244008Srmacklem error = EPIPE; 931244008Srmacklem sx_xunlock(&xprt->xp_lock); 932244008Srmacklem if (!error) { 933244008Srmacklem stat = TRUE; 934244008Srmacklem } 935244008Srmacklem } else { 936244008Srmacklem m_freem(mrep); 937244008Srmacklem } 938244008Srmacklem 939244008Srmacklem XDR_DESTROY(&xdrs); 940244008Srmacklem 941244008Srmacklem return (stat); 942244008Srmacklem} 943244008Srmacklem 944244008Srmacklemstatic bool_t 945177633Sdfrsvc_vc_null() 946177633Sdfr{ 947177633Sdfr 948177633Sdfr return (FALSE); 949177633Sdfr} 950177633Sdfr 951193272Sjhbstatic int 952177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 953177633Sdfr{ 954177633Sdfr SVCXPRT *xprt = (SVCXPRT *) arg; 955177633Sdfr 956261047Smav if (soreadable(xprt->xp_socket)) 957261047Smav xprt_active(xprt); 958193272Sjhb return (SU_OK); 959177633Sdfr} 960177633Sdfr 961177633Sdfr#if 0 962177633Sdfr/* 963177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv 964177633Sdfr * and rpc.yppasswdd on AF_LOCAL. 965177633Sdfr */ 966177633Sdfrint 967177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 968177633Sdfr int sock, ret; 969177633Sdfr gid_t egid; 970177633Sdfr uid_t euid; 971177633Sdfr struct sockaddr *sa; 972177633Sdfr 973177633Sdfr sock = transp->xp_fd; 974184588Sdfr sa = (struct sockaddr *)transp->xp_rtaddr; 975177633Sdfr if (sa->sa_family == AF_LOCAL) { 976177633Sdfr ret = getpeereid(sock, &euid, &egid); 977177633Sdfr if (ret == 0) 978177633Sdfr *uid = euid; 979177633Sdfr return (ret); 980177633Sdfr } else 981177633Sdfr return (-1); 982177633Sdfr} 983177633Sdfr#endif 984