17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2161961e0fSrobinson 227c478bd9Sstevel@tonic-gate /* 23*09b0d01cSGary Mills * Copyright 2014 Gary Mills 243669bedeSViswanathan Kannappan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 317c478bd9Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of 327c478bd9Sstevel@tonic-gate * California. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate /* 367c478bd9Sstevel@tonic-gate * svc_dg.c, Server side for connectionless RPC. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Does some caching in the hopes of achieving execute-at-most-once semantics. 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include "mt.h" 427c478bd9Sstevel@tonic-gate #include "rpc_mt.h" 437c478bd9Sstevel@tonic-gate #include <stdio.h> 447c478bd9Sstevel@tonic-gate #include <sys/types.h> 4545916cd2Sjpk #include <sys/sysmacros.h> 467c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 47f48205beScasper #include <rpcsvc/svc_dg_priv.h> 487c478bd9Sstevel@tonic-gate #include <errno.h> 497c478bd9Sstevel@tonic-gate #include <syslog.h> 507c478bd9Sstevel@tonic-gate #include <stdlib.h> 517c478bd9Sstevel@tonic-gate #include <string.h> 5267dbe2beSCasper H.S. Dik #include <ucred.h> 537c478bd9Sstevel@tonic-gate #include <unistd.h> 543669bedeSViswanathan Kannappan #include <sys/socket.h> 553669bedeSViswanathan Kannappan #include <netinet/in.h> 563669bedeSViswanathan Kannappan #include <arpa/inet.h> 577c478bd9Sstevel@tonic-gate #ifdef RPC_CACHE_DEBUG 587c478bd9Sstevel@tonic-gate #include <netconfig.h> 597c478bd9Sstevel@tonic-gate #include <netdir.h> 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #ifndef MAX 637c478bd9Sstevel@tonic-gate #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 647c478bd9Sstevel@tonic-gate #endif 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static struct xp_ops *svc_dg_ops(); 677c478bd9Sstevel@tonic-gate static void cache_set(); 687c478bd9Sstevel@tonic-gate static int cache_get(); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #define rpc_buffer(xprt) ((xprt)->xp_p1) 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * Usage: 747c478bd9Sstevel@tonic-gate * xprt = svc_dg_create(sock, sendsize, recvsize); 757c478bd9Sstevel@tonic-gate * Does other connectionless specific initializations. 767c478bd9Sstevel@tonic-gate * Once *xprt is initialized, it is registered. 777c478bd9Sstevel@tonic-gate * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable 787c478bd9Sstevel@tonic-gate * system defaults are chosen. 797c478bd9Sstevel@tonic-gate * The routines returns NULL if a problem occurred. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate static const char svc_dg_str[] = "svc_dg_create: %s"; 827c478bd9Sstevel@tonic-gate static const char svc_dg_err1[] = "could not get transport information"; 837c478bd9Sstevel@tonic-gate static const char svc_dg_err2[] = " transport does not support data transfer"; 847c478bd9Sstevel@tonic-gate static const char svc_dg_err3[] = 857c478bd9Sstevel@tonic-gate "fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);"; 867c478bd9Sstevel@tonic-gate static const char __no_mem_str[] = "out of memory"; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */ 897c478bd9Sstevel@tonic-gate extern struct svc_auth_ops svc_auth_any_ops; 907c478bd9Sstevel@tonic-gate extern int __rpc_get_ltaddr(struct netbuf *, struct netbuf *); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate void 9361961e0fSrobinson svc_dg_xprtfree(SVCXPRT *xprt) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 967c478bd9Sstevel@tonic-gate SVCXPRT_EXT *xt = xprt ? SVCEXT(xprt) : NULL; 977c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 98f48205beScasper struct svc_dg_data *su = xprt ? get_svc_dg_data(xprt) : NULL; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate if (xprt == NULL) 1017c478bd9Sstevel@tonic-gate return; 1027c478bd9Sstevel@tonic-gate if (xprt->xp_netid) 10361961e0fSrobinson free(xprt->xp_netid); 1047c478bd9Sstevel@tonic-gate if (xprt->xp_tp) 10561961e0fSrobinson free(xprt->xp_tp); 1067c478bd9Sstevel@tonic-gate if (xt->parent == NULL) 1077c478bd9Sstevel@tonic-gate if (xprt->xp_ltaddr.buf) 1087c478bd9Sstevel@tonic-gate free(xprt->xp_ltaddr.buf); 1097c478bd9Sstevel@tonic-gate if (xprt->xp_rtaddr.buf) 1107c478bd9Sstevel@tonic-gate free(xprt->xp_rtaddr.buf); 1117c478bd9Sstevel@tonic-gate if (su != NULL) { 1127c478bd9Sstevel@tonic-gate XDR_DESTROY(&(su->su_xdrs)); 11361961e0fSrobinson free(su); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate if (rpc_buffer(xprt)) 11661961e0fSrobinson free(rpc_buffer(xprt)); 1177c478bd9Sstevel@tonic-gate svc_xprt_free(xprt); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate SVCXPRT * 12161961e0fSrobinson svc_dg_create_private(int fd, uint_t sendsize, uint_t recvsize) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 1247c478bd9Sstevel@tonic-gate struct svc_dg_data *su = NULL; 1257c478bd9Sstevel@tonic-gate struct t_info tinfo; 12667dbe2beSCasper H.S. Dik size_t ucred_sz = ucred_size(); 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate if (RPC_FD_NOTIN_FDSET(fd)) { 1297c478bd9Sstevel@tonic-gate errno = EBADF; 1307c478bd9Sstevel@tonic-gate t_errno = TBADF; 1317c478bd9Sstevel@tonic-gate syslog(LOG_ERR, svc_dg_str, svc_dg_err3); 13261961e0fSrobinson return (NULL); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate if (t_getinfo(fd, &tinfo) == -1) { 1367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, svc_dg_str, svc_dg_err1); 13761961e0fSrobinson return (NULL); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Find the receive and the send size 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu); 1437c478bd9Sstevel@tonic-gate recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu); 1447c478bd9Sstevel@tonic-gate if ((sendsize == 0) || (recvsize == 0)) { 1457c478bd9Sstevel@tonic-gate syslog(LOG_ERR, svc_dg_str, svc_dg_err2); 14661961e0fSrobinson return (NULL); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate if ((xprt = svc_xprt_alloc()) == NULL) 1507c478bd9Sstevel@tonic-gate goto freedata; 1517c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 1527c478bd9Sstevel@tonic-gate svc_flags(xprt) |= SVC_DGRAM; 1537c478bd9Sstevel@tonic-gate 15467dbe2beSCasper H.S. Dik su = malloc(sizeof (*su) + ucred_sz); 1557c478bd9Sstevel@tonic-gate if (su == NULL) 1567c478bd9Sstevel@tonic-gate goto freedata; 1577c478bd9Sstevel@tonic-gate su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; 15861961e0fSrobinson if ((rpc_buffer(xprt) = malloc(su->su_iosz)) == NULL) 1597c478bd9Sstevel@tonic-gate goto freedata; 1607c478bd9Sstevel@tonic-gate xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, 1617c478bd9Sstevel@tonic-gate XDR_DECODE); 1627c478bd9Sstevel@tonic-gate su->su_cache = NULL; 1637c478bd9Sstevel@tonic-gate xprt->xp_fd = fd; 1647c478bd9Sstevel@tonic-gate xprt->xp_p2 = (caddr_t)su; 1657c478bd9Sstevel@tonic-gate xprt->xp_verf.oa_base = su->su_verfbody; 1667c478bd9Sstevel@tonic-gate xprt->xp_ops = svc_dg_ops(); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate su->su_tudata.addr.maxlen = 0; /* Fill in later */ 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate su->su_tudata.udata.buf = (char *)rpc_buffer(xprt); 1717c478bd9Sstevel@tonic-gate su->su_tudata.opt.buf = (char *)su->opts; 1727c478bd9Sstevel@tonic-gate su->su_tudata.udata.maxlen = su->su_iosz; 17367dbe2beSCasper H.S. Dik su->su_tudata.opt.maxlen = MAX_OPT_WORDS * sizeof (int) + ucred_sz; 1747c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 1757c478bd9Sstevel@tonic-gate SVC_XP_AUTH(xprt).svc_ah_ops = svc_auth_any_ops; 1767c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 1777c478bd9Sstevel@tonic-gate SVC_XP_AUTH(xprt).svc_ah_private = NULL; 1787c478bd9Sstevel@tonic-gate return (xprt); 1797c478bd9Sstevel@tonic-gate freedata: 1807c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, svc_dg_str, __no_mem_str); 1817c478bd9Sstevel@tonic-gate if (xprt) 1827c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 18361961e0fSrobinson return (NULL); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate SVCXPRT * 18761961e0fSrobinson svc_dg_create(const int fd, const uint_t sendsize, const uint_t recvsize) 1887c478bd9Sstevel@tonic-gate { 1897c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if ((xprt = svc_dg_create_private(fd, sendsize, recvsize)) != NULL) 1927c478bd9Sstevel@tonic-gate xprt_register(xprt); 1937c478bd9Sstevel@tonic-gate return (xprt); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate SVCXPRT * 19761961e0fSrobinson svc_dg_xprtcopy(SVCXPRT *parent) 1987c478bd9Sstevel@tonic-gate { 1997c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 2007c478bd9Sstevel@tonic-gate struct svc_dg_data *su; 20167dbe2beSCasper H.S. Dik size_t ucred_sz = ucred_size(); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if ((xprt = svc_xprt_alloc()) == NULL) 2047c478bd9Sstevel@tonic-gate return (NULL); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 2077c478bd9Sstevel@tonic-gate SVCEXT(xprt)->parent = parent; 2087c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 2097c478bd9Sstevel@tonic-gate SVCEXT(xprt)->flags = SVCEXT(parent)->flags; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate xprt->xp_fd = parent->xp_fd; 2127c478bd9Sstevel@tonic-gate xprt->xp_port = parent->xp_port; 2137c478bd9Sstevel@tonic-gate xprt->xp_ops = svc_dg_ops(); 2147c478bd9Sstevel@tonic-gate if (parent->xp_tp) { 2157c478bd9Sstevel@tonic-gate xprt->xp_tp = (char *)strdup(parent->xp_tp); 2167c478bd9Sstevel@tonic-gate if (xprt->xp_tp == NULL) { 2177c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_dg_xprtcopy: strdup failed"); 2187c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 2197c478bd9Sstevel@tonic-gate return (NULL); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate if (parent->xp_netid) { 2237c478bd9Sstevel@tonic-gate xprt->xp_netid = (char *)strdup(parent->xp_netid); 2247c478bd9Sstevel@tonic-gate if (xprt->xp_netid == NULL) { 2257c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_dg_xprtcopy: strdup failed"); 2267c478bd9Sstevel@tonic-gate if (parent->xp_tp) 2277c478bd9Sstevel@tonic-gate free(parent->xp_tp); 2287c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 2297c478bd9Sstevel@tonic-gate return (NULL); 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate xprt->xp_ltaddr = parent->xp_ltaddr; /* shared with parent */ 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate xprt->xp_rtaddr = parent->xp_rtaddr; 23561961e0fSrobinson xprt->xp_rtaddr.buf = malloc(xprt->xp_rtaddr.maxlen); 2367c478bd9Sstevel@tonic-gate if (xprt->xp_rtaddr.buf == NULL) { 2377c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 2387c478bd9Sstevel@tonic-gate return (NULL); 2397c478bd9Sstevel@tonic-gate } 24061961e0fSrobinson (void) memcpy(xprt->xp_rtaddr.buf, parent->xp_rtaddr.buf, 2417c478bd9Sstevel@tonic-gate xprt->xp_rtaddr.maxlen); 2427c478bd9Sstevel@tonic-gate xprt->xp_type = parent->xp_type; 2437c478bd9Sstevel@tonic-gate 24467dbe2beSCasper H.S. Dik if ((su = malloc(sizeof (struct svc_dg_data) + ucred_sz)) == NULL) { 2457c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 2467c478bd9Sstevel@tonic-gate return (NULL); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 249f48205beScasper su->su_iosz = get_svc_dg_data(parent)->su_iosz; 25061961e0fSrobinson if ((rpc_buffer(xprt) = malloc(su->su_iosz)) == NULL) { 2517c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 25261961e0fSrobinson free(su); 2537c478bd9Sstevel@tonic-gate return (NULL); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, 2567c478bd9Sstevel@tonic-gate XDR_DECODE); 2577c478bd9Sstevel@tonic-gate su->su_cache = NULL; 2587c478bd9Sstevel@tonic-gate su->su_tudata.addr.maxlen = 0; /* Fill in later */ 2597c478bd9Sstevel@tonic-gate su->su_tudata.udata.buf = (char *)rpc_buffer(xprt); 2607c478bd9Sstevel@tonic-gate su->su_tudata.opt.buf = (char *)su->opts; 2617c478bd9Sstevel@tonic-gate su->su_tudata.udata.maxlen = su->su_iosz; 26267dbe2beSCasper H.S. Dik su->su_tudata.opt.maxlen = MAX_OPT_WORDS * sizeof (int) + ucred_sz; 263f48205beScasper xprt->xp_p2 = (caddr_t)su; /* get_svc_dg_data(xprt) = su */ 2647c478bd9Sstevel@tonic-gate xprt->xp_verf.oa_base = su->su_verfbody; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate return (xprt); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2707c478bd9Sstevel@tonic-gate static enum xprt_stat 27161961e0fSrobinson svc_dg_stat(SVCXPRT *xprt) 2727c478bd9Sstevel@tonic-gate { 2737c478bd9Sstevel@tonic-gate return (XPRT_IDLE); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 27645916cd2Sjpk /* 27745916cd2Sjpk * Find the SCM_UCRED in src and place a pointer to that option alone in dest. 27845916cd2Sjpk * Note that these two 'netbuf' structures might be the same one, so the code 27945916cd2Sjpk * has to be careful about referring to src after changing dest. 28045916cd2Sjpk */ 28145916cd2Sjpk static void 28245916cd2Sjpk extract_cred(const struct netbuf *src, struct netbuf *dest) 28345916cd2Sjpk { 28445916cd2Sjpk char *cp = src->buf; 28545916cd2Sjpk unsigned int len = src->len; 28645916cd2Sjpk const struct T_opthdr *opt; 28745916cd2Sjpk unsigned int olen; 28845916cd2Sjpk 28945916cd2Sjpk while (len >= sizeof (*opt)) { 29045916cd2Sjpk /* LINTED: pointer alignment */ 29145916cd2Sjpk opt = (const struct T_opthdr *)cp; 29245916cd2Sjpk olen = opt->len; 29345916cd2Sjpk if (olen > len || olen < sizeof (*opt) || 29445916cd2Sjpk !IS_P2ALIGNED(olen, sizeof (t_uscalar_t))) 29545916cd2Sjpk break; 29645916cd2Sjpk if (opt->level == SOL_SOCKET && opt->name == SCM_UCRED) { 29745916cd2Sjpk dest->buf = cp; 29845916cd2Sjpk dest->len = olen; 29945916cd2Sjpk return; 30045916cd2Sjpk } 30145916cd2Sjpk cp += olen; 30245916cd2Sjpk len -= olen; 30345916cd2Sjpk } 30445916cd2Sjpk dest->len = 0; 30545916cd2Sjpk } 30645916cd2Sjpk 3073669bedeSViswanathan Kannappan /* 3083669bedeSViswanathan Kannappan * This routine extracts the destination IP address of the inbound RPC packet 3093669bedeSViswanathan Kannappan * and sets that as source IP address for the outbound response. 3103669bedeSViswanathan Kannappan */ 3113669bedeSViswanathan Kannappan static void 3123669bedeSViswanathan Kannappan set_src_addr(SVCXPRT *xprt, struct netbuf *opt) 3133669bedeSViswanathan Kannappan { 3143669bedeSViswanathan Kannappan struct netbuf *nbufp, *ltaddr; 3153669bedeSViswanathan Kannappan struct T_opthdr *opthdr; 3163669bedeSViswanathan Kannappan in_pktinfo_t *pktinfo; 3173669bedeSViswanathan Kannappan struct sockaddr_in *sock = (struct sockaddr_in *)NULL; 3183669bedeSViswanathan Kannappan 3193669bedeSViswanathan Kannappan /* extract dest IP of inbound packet */ 3203669bedeSViswanathan Kannappan /* LINTED pointer alignment */ 3213669bedeSViswanathan Kannappan nbufp = (struct netbuf *)xprt->xp_p2; 3223669bedeSViswanathan Kannappan ltaddr = &xprt->xp_ltaddr; 3233669bedeSViswanathan Kannappan if (__rpc_get_ltaddr(nbufp, ltaddr) != 0) 3243669bedeSViswanathan Kannappan return; 3253669bedeSViswanathan Kannappan 3263669bedeSViswanathan Kannappan /* do nothing for non-IPv4 packet */ 3273669bedeSViswanathan Kannappan /* LINTED pointer alignment */ 3283669bedeSViswanathan Kannappan sock = (struct sockaddr_in *)ltaddr->buf; 3293669bedeSViswanathan Kannappan if (sock->sin_family != AF_INET) 3303669bedeSViswanathan Kannappan return; 3313669bedeSViswanathan Kannappan 3323669bedeSViswanathan Kannappan /* set desired option header */ 3333669bedeSViswanathan Kannappan opthdr = (struct T_opthdr *)memalign(sizeof (int), 3343669bedeSViswanathan Kannappan sizeof (struct T_opthdr) + sizeof (in_pktinfo_t)); 3353669bedeSViswanathan Kannappan if (opthdr == NULL) 3363669bedeSViswanathan Kannappan return; 3373669bedeSViswanathan Kannappan opthdr->len = sizeof (struct T_opthdr) + sizeof (in_pktinfo_t); 3383669bedeSViswanathan Kannappan opthdr->level = IPPROTO_IP; 3393669bedeSViswanathan Kannappan opthdr->name = IP_PKTINFO; 3403669bedeSViswanathan Kannappan 3413669bedeSViswanathan Kannappan /* 3423669bedeSViswanathan Kannappan * 1. set source IP of outbound packet 3433669bedeSViswanathan Kannappan * 2. value '0' for index means IP layer uses this as source address 3443669bedeSViswanathan Kannappan */ 3453669bedeSViswanathan Kannappan pktinfo = (in_pktinfo_t *)(opthdr + 1); 3463669bedeSViswanathan Kannappan (void) memset(pktinfo, 0, sizeof (in_pktinfo_t)); 3473669bedeSViswanathan Kannappan pktinfo->ipi_spec_dst.s_addr = sock->sin_addr.s_addr; 3483669bedeSViswanathan Kannappan pktinfo->ipi_ifindex = 0; 3493669bedeSViswanathan Kannappan 3503669bedeSViswanathan Kannappan /* copy data into ancillary buffer */ 3513669bedeSViswanathan Kannappan if (opthdr->len + opt->len <= opt->maxlen) { 3523669bedeSViswanathan Kannappan (void) memcpy((void *)(opt->buf+opt->len), (const void *)opthdr, 3533669bedeSViswanathan Kannappan opthdr->len); 3543669bedeSViswanathan Kannappan opt->len += opthdr->len; 3553669bedeSViswanathan Kannappan } 3563669bedeSViswanathan Kannappan free(opthdr); 3573669bedeSViswanathan Kannappan } 3583669bedeSViswanathan Kannappan 3597c478bd9Sstevel@tonic-gate static bool_t 36061961e0fSrobinson svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg) 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 363f48205beScasper struct svc_dg_data *su = get_svc_dg_data(xprt); 3647c478bd9Sstevel@tonic-gate XDR *xdrs = &(su->su_xdrs); 3657c478bd9Sstevel@tonic-gate struct t_unitdata *tu_data = &(su->su_tudata); 3667c478bd9Sstevel@tonic-gate int moreflag; 3677c478bd9Sstevel@tonic-gate struct netbuf *nbufp; 3687c478bd9Sstevel@tonic-gate struct netconfig *nconf; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate /* XXX: tudata should have been made a part of the server handle */ 3717c478bd9Sstevel@tonic-gate if (tu_data->addr.maxlen == 0) 3727c478bd9Sstevel@tonic-gate tu_data->addr = xprt->xp_rtaddr; 3737c478bd9Sstevel@tonic-gate again: 3747c478bd9Sstevel@tonic-gate tu_data->addr.len = 0; 3757c478bd9Sstevel@tonic-gate tu_data->opt.len = 0; 3767c478bd9Sstevel@tonic-gate tu_data->udata.len = 0; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate moreflag = 0; 3797c478bd9Sstevel@tonic-gate if (t_rcvudata(xprt->xp_fd, tu_data, &moreflag) == -1) { 3807c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG 3817c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_dg_recv: t_rcvudata t_errno=%d errno=%d\n", 3827c478bd9Sstevel@tonic-gate t_errno, errno); 3837c478bd9Sstevel@tonic-gate #endif 3847c478bd9Sstevel@tonic-gate if (t_errno == TLOOK) { 3857c478bd9Sstevel@tonic-gate int lookres; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate lookres = t_look(xprt->xp_fd); 388*09b0d01cSGary Mills if ((lookres == T_UDERR) && 3897c478bd9Sstevel@tonic-gate (t_rcvuderr(xprt->xp_fd, 3907c478bd9Sstevel@tonic-gate (struct t_uderr *)0) < 0)) { 3917c478bd9Sstevel@tonic-gate /*EMPTY*/ 3927c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG 3937c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 3947c478bd9Sstevel@tonic-gate "svc_dg_recv: t_rcvuderr t_errno = %d\n", 3957c478bd9Sstevel@tonic-gate t_errno); 3967c478bd9Sstevel@tonic-gate #endif 3977c478bd9Sstevel@tonic-gate } 398*09b0d01cSGary Mills if (lookres == T_DATA) 3997c478bd9Sstevel@tonic-gate goto again; 4007c478bd9Sstevel@tonic-gate } else if ((errno == EINTR) && (t_errno == TSYSERR)) 4017c478bd9Sstevel@tonic-gate goto again; 4027c478bd9Sstevel@tonic-gate else { 4037c478bd9Sstevel@tonic-gate return (FALSE); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate if ((moreflag) || 4087c478bd9Sstevel@tonic-gate (tu_data->udata.len < 4 * (uint_t)sizeof (uint32_t))) { 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * If moreflag is set, drop that data packet. Something wrong 4117c478bd9Sstevel@tonic-gate */ 4127c478bd9Sstevel@tonic-gate return (FALSE); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate su->optbuf = tu_data->opt; 4157c478bd9Sstevel@tonic-gate xprt->xp_rtaddr.len = tu_data->addr.len; 4167c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_DECODE; 4177c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, 0); 41861961e0fSrobinson if (!xdr_callmsg(xdrs, msg)) 4197c478bd9Sstevel@tonic-gate return (FALSE); 4207c478bd9Sstevel@tonic-gate su->su_xid = msg->rm_xid; 4217c478bd9Sstevel@tonic-gate if (su->su_cache != NULL) { 4227c478bd9Sstevel@tonic-gate char *reply; 4237c478bd9Sstevel@tonic-gate uint32_t replylen; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate if (cache_get(xprt, msg, &reply, &replylen)) { 4267c478bd9Sstevel@tonic-gate /* tu_data.addr is already set */ 4277c478bd9Sstevel@tonic-gate tu_data->udata.buf = reply; 4287c478bd9Sstevel@tonic-gate tu_data->udata.len = (uint_t)replylen; 42945916cd2Sjpk extract_cred(&tu_data->opt, &tu_data->opt); 4303669bedeSViswanathan Kannappan set_src_addr(xprt, &tu_data->opt); 4317c478bd9Sstevel@tonic-gate (void) t_sndudata(xprt->xp_fd, tu_data); 4327c478bd9Sstevel@tonic-gate tu_data->udata.buf = (char *)rpc_buffer(xprt); 43345916cd2Sjpk tu_data->opt.buf = (char *)su->opts; 4347c478bd9Sstevel@tonic-gate return (FALSE); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * get local ip address 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate if ((nconf = getnetconfigent(xprt->xp_netid)) != NULL) { 4437c478bd9Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0 || 4447c478bd9Sstevel@tonic-gate strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 4457c478bd9Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_CLTS) { 44661961e0fSrobinson /* LINTED pointer cast */ 4477c478bd9Sstevel@tonic-gate nbufp = (struct netbuf *)(xprt->xp_p2); 4483669bedeSViswanathan Kannappan if (__rpc_get_ltaddr(nbufp, 4493669bedeSViswanathan Kannappan &xprt->xp_ltaddr) < 0) { 4503669bedeSViswanathan Kannappan if (strcmp(nconf->nc_protofmly, 4513669bedeSViswanathan Kannappan NC_INET) == 0) { 4527c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 4533669bedeSViswanathan Kannappan "svc_dg_recv: ip(udp), " 4543669bedeSViswanathan Kannappan "t_errno=%d, errno=%d", 4557c478bd9Sstevel@tonic-gate t_errno, errno); 4567c478bd9Sstevel@tonic-gate } 4573669bedeSViswanathan Kannappan if (strcmp(nconf->nc_protofmly, 4583669bedeSViswanathan Kannappan NC_INET6) == 0) { 4597c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 4603669bedeSViswanathan Kannappan "svc_dg_recv: ip (udp6), " 4613669bedeSViswanathan Kannappan "t_errno=%d, errno=%d", 4627c478bd9Sstevel@tonic-gate t_errno, errno); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 4657c478bd9Sstevel@tonic-gate return (FALSE); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate return (TRUE); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate static bool_t 47561961e0fSrobinson svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 478f48205beScasper struct svc_dg_data *su = get_svc_dg_data(xprt); 4797c478bd9Sstevel@tonic-gate XDR *xdrs = &(su->su_xdrs); 4807c478bd9Sstevel@tonic-gate bool_t stat = FALSE; 4817c478bd9Sstevel@tonic-gate xdrproc_t xdr_results; 4827c478bd9Sstevel@tonic-gate caddr_t xdr_location; 4837c478bd9Sstevel@tonic-gate bool_t has_args; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 4867c478bd9Sstevel@tonic-gate msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 4877c478bd9Sstevel@tonic-gate has_args = TRUE; 4887c478bd9Sstevel@tonic-gate xdr_results = msg->acpted_rply.ar_results.proc; 4897c478bd9Sstevel@tonic-gate xdr_location = msg->acpted_rply.ar_results.where; 4907c478bd9Sstevel@tonic-gate msg->acpted_rply.ar_results.proc = xdr_void; 4917c478bd9Sstevel@tonic-gate msg->acpted_rply.ar_results.where = NULL; 4927c478bd9Sstevel@tonic-gate } else 4937c478bd9Sstevel@tonic-gate has_args = FALSE; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 4967c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, 0); 4977c478bd9Sstevel@tonic-gate msg->rm_xid = su->su_xid; 4987c478bd9Sstevel@tonic-gate if (xdr_replymsg(xdrs, msg) && (!has_args || 4997c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 5007c478bd9Sstevel@tonic-gate SVCAUTH_WRAP(&SVC_XP_AUTH(xprt), xdrs, xdr_results, 5017c478bd9Sstevel@tonic-gate xdr_location))) { 5027c478bd9Sstevel@tonic-gate int slen; 5037c478bd9Sstevel@tonic-gate struct t_unitdata *tu_data = &(su->su_tudata); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate slen = (int)XDR_GETPOS(xdrs); 5067c478bd9Sstevel@tonic-gate tu_data->udata.len = slen; 50745916cd2Sjpk extract_cred(&su->optbuf, &tu_data->opt); 5083669bedeSViswanathan Kannappan set_src_addr(xprt, &tu_data->opt); 5097c478bd9Sstevel@tonic-gate try_again: 5107c478bd9Sstevel@tonic-gate if (t_sndudata(xprt->xp_fd, tu_data) == 0) { 5117c478bd9Sstevel@tonic-gate stat = TRUE; 5127c478bd9Sstevel@tonic-gate if (su->su_cache && slen >= 0) { 5137c478bd9Sstevel@tonic-gate cache_set(xprt, (uint32_t)slen); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate } else { 5167c478bd9Sstevel@tonic-gate if (errno == EINTR) 5177c478bd9Sstevel@tonic-gate goto try_again; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 5203669bedeSViswanathan Kannappan "svc_dg_reply: t_sndudata error t_errno=%d ", 5213669bedeSViswanathan Kannappan "errno=%d\n", t_errno, errno); 5227c478bd9Sstevel@tonic-gate } 52345916cd2Sjpk tu_data->opt.buf = (char *)su->opts; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate return (stat); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate static bool_t 52961961e0fSrobinson svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 5307c478bd9Sstevel@tonic-gate { 5317c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE) 5327c478bd9Sstevel@tonic-gate svc_args_done(xprt); 5337c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 53461961e0fSrobinson return (SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt), 5353669bedeSViswanathan Kannappan &(get_svc_dg_data(xprt)->su_xdrs), xdr_args, args_ptr)); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate static bool_t 53961961e0fSrobinson svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 5407c478bd9Sstevel@tonic-gate { 5417c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 542f48205beScasper XDR *xdrs = &(get_svc_dg_data(xprt)->su_xdrs); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 54561961e0fSrobinson return ((*xdr_args)(xdrs, args_ptr)); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate static void 54961961e0fSrobinson svc_dg_destroy(SVCXPRT *xprt) 5507c478bd9Sstevel@tonic-gate { 55161961e0fSrobinson (void) mutex_lock(&svc_mutex); 5527c478bd9Sstevel@tonic-gate _svc_dg_destroy_private(xprt); 55361961e0fSrobinson (void) mutex_unlock(&svc_mutex); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate void 55761961e0fSrobinson _svc_dg_destroy_private(SVCXPRT *xprt) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE) { 5607c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 5617c478bd9Sstevel@tonic-gate if (SVCEXT(xprt)->parent) 5627c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 5637c478bd9Sstevel@tonic-gate xprt = SVCEXT(xprt)->parent; 5647c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 5657c478bd9Sstevel@tonic-gate svc_flags(xprt) |= SVC_DEFUNCT; 5667c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 5677c478bd9Sstevel@tonic-gate if (SVCEXT(xprt)->refcnt > 0) 5687c478bd9Sstevel@tonic-gate return; 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate xprt_unregister(xprt); 5727c478bd9Sstevel@tonic-gate (void) t_close(xprt->xp_fd); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE) 5757c478bd9Sstevel@tonic-gate svc_xprt_destroy(xprt); 5767c478bd9Sstevel@tonic-gate else 5777c478bd9Sstevel@tonic-gate svc_dg_xprtfree(xprt); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5817c478bd9Sstevel@tonic-gate static bool_t 58261961e0fSrobinson svc_dg_control(SVCXPRT *xprt, const uint_t rq, void *in) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate switch (rq) { 5857c478bd9Sstevel@tonic-gate case SVCGET_XID: 58661961e0fSrobinson if (xprt->xp_p2 == NULL) 5877c478bd9Sstevel@tonic-gate return (FALSE); 5887c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 58961961e0fSrobinson *(uint32_t *)in = ((struct svc_dg_data *)(xprt->xp_p2))->su_xid; 5907c478bd9Sstevel@tonic-gate return (TRUE); 5917c478bd9Sstevel@tonic-gate default: 5927c478bd9Sstevel@tonic-gate return (FALSE); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate static struct xp_ops * 59761961e0fSrobinson svc_dg_ops(void) 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate static struct xp_ops ops; 6007c478bd9Sstevel@tonic-gate extern mutex_t ops_lock; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY ops_lock: ops */ 6037c478bd9Sstevel@tonic-gate 60461961e0fSrobinson (void) mutex_lock(&ops_lock); 6057c478bd9Sstevel@tonic-gate if (ops.xp_recv == NULL) { 6067c478bd9Sstevel@tonic-gate ops.xp_recv = svc_dg_recv; 6077c478bd9Sstevel@tonic-gate ops.xp_stat = svc_dg_stat; 6087c478bd9Sstevel@tonic-gate ops.xp_getargs = svc_dg_getargs; 6097c478bd9Sstevel@tonic-gate ops.xp_reply = svc_dg_reply; 6107c478bd9Sstevel@tonic-gate ops.xp_freeargs = svc_dg_freeargs; 6117c478bd9Sstevel@tonic-gate ops.xp_destroy = svc_dg_destroy; 6127c478bd9Sstevel@tonic-gate ops.xp_control = svc_dg_control; 6137c478bd9Sstevel@tonic-gate } 61461961e0fSrobinson (void) mutex_unlock(&ops_lock); 6157c478bd9Sstevel@tonic-gate return (&ops); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate /* The CACHING COMPONENT */ 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate /* 6217c478bd9Sstevel@tonic-gate * Could have been a separate file, but some part of it depends upon the 6227c478bd9Sstevel@tonic-gate * private structure of the client handle. 6237c478bd9Sstevel@tonic-gate * 6247c478bd9Sstevel@tonic-gate * Fifo cache for cl server 6257c478bd9Sstevel@tonic-gate * Copies pointers to reply buffers into fifo cache 6267c478bd9Sstevel@tonic-gate * Buffers are sent again if retransmissions are detected. 6277c478bd9Sstevel@tonic-gate */ 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate #define SPARSENESS 4 /* 75% sparse */ 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * An entry in the cache 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate typedef struct cache_node *cache_ptr; 6357c478bd9Sstevel@tonic-gate struct cache_node { 6367c478bd9Sstevel@tonic-gate /* 6377c478bd9Sstevel@tonic-gate * Index into cache is xid, proc, vers, prog and address 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate uint32_t cache_xid; 6407c478bd9Sstevel@tonic-gate rpcproc_t cache_proc; 6417c478bd9Sstevel@tonic-gate rpcvers_t cache_vers; 6427c478bd9Sstevel@tonic-gate rpcprog_t cache_prog; 6437c478bd9Sstevel@tonic-gate struct netbuf cache_addr; 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * The cached reply and length 6467c478bd9Sstevel@tonic-gate */ 6477c478bd9Sstevel@tonic-gate char *cache_reply; 6487c478bd9Sstevel@tonic-gate uint32_t cache_replylen; 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * Next node on the list, if there is a collision 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate cache_ptr cache_next; 6537c478bd9Sstevel@tonic-gate }; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * The entire cache 6577c478bd9Sstevel@tonic-gate */ 6587c478bd9Sstevel@tonic-gate struct cl_cache { 6597c478bd9Sstevel@tonic-gate uint32_t uc_size; /* size of cache */ 6607c478bd9Sstevel@tonic-gate cache_ptr *uc_entries; /* hash table of entries in cache */ 6617c478bd9Sstevel@tonic-gate cache_ptr *uc_fifo; /* fifo list of entries in cache */ 6627c478bd9Sstevel@tonic-gate uint32_t uc_nextvictim; /* points to next victim in fifo list */ 6637c478bd9Sstevel@tonic-gate rpcprog_t uc_prog; /* saved program number */ 6647c478bd9Sstevel@tonic-gate rpcvers_t uc_vers; /* saved version number */ 6657c478bd9Sstevel@tonic-gate rpcproc_t uc_proc; /* saved procedure number */ 6667c478bd9Sstevel@tonic-gate }; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * the hashing function 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate #define CACHE_LOC(transp, xid) \ 6737c478bd9Sstevel@tonic-gate (xid % (SPARSENESS * ((struct cl_cache *) \ 674f48205beScasper get_svc_dg_data(transp)->su_cache)->uc_size)) 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate extern mutex_t dupreq_lock; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * Enable use of the cache. Returns 1 on success, 0 on failure. 6807c478bd9Sstevel@tonic-gate * Note: there is no disable. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate static const char cache_enable_str[] = "svc_enablecache: %s %s"; 6837c478bd9Sstevel@tonic-gate static const char alloc_err[] = "could not allocate cache "; 6847c478bd9Sstevel@tonic-gate static const char enable_err[] = "cache already enabled"; 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate int 68761961e0fSrobinson svc_dg_enablecache(SVCXPRT *xprt, const uint_t size) 6887c478bd9Sstevel@tonic-gate { 6897c478bd9Sstevel@tonic-gate SVCXPRT *transp; 6907c478bd9Sstevel@tonic-gate struct svc_dg_data *su; 6917c478bd9Sstevel@tonic-gate struct cl_cache *uc; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 6947c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE && SVCEXT(xprt)->parent != NULL) 6957c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 6967c478bd9Sstevel@tonic-gate transp = SVCEXT(xprt)->parent; 6977c478bd9Sstevel@tonic-gate else 6987c478bd9Sstevel@tonic-gate transp = xprt; 6997c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 700f48205beScasper su = get_svc_dg_data(transp); 7017c478bd9Sstevel@tonic-gate 70261961e0fSrobinson (void) mutex_lock(&dupreq_lock); 7037c478bd9Sstevel@tonic-gate if (su->su_cache != NULL) { 7047c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, cache_enable_str, 7057c478bd9Sstevel@tonic-gate enable_err, " "); 70661961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 7077c478bd9Sstevel@tonic-gate return (0); 7087c478bd9Sstevel@tonic-gate } 70961961e0fSrobinson uc = malloc(sizeof (struct cl_cache)); 7107c478bd9Sstevel@tonic-gate if (uc == NULL) { 7117c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, cache_enable_str, 7127c478bd9Sstevel@tonic-gate alloc_err, " "); 71361961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 7147c478bd9Sstevel@tonic-gate return (0); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate uc->uc_size = size; 7177c478bd9Sstevel@tonic-gate uc->uc_nextvictim = 0; 71861961e0fSrobinson uc->uc_entries = calloc(size * SPARSENESS, sizeof (cache_ptr)); 7197c478bd9Sstevel@tonic-gate if (uc->uc_entries == NULL) { 72061961e0fSrobinson (void) syslog(LOG_ERR, cache_enable_str, alloc_err, "data"); 72161961e0fSrobinson free(uc); 72261961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 7237c478bd9Sstevel@tonic-gate return (0); 7247c478bd9Sstevel@tonic-gate } 72561961e0fSrobinson uc->uc_fifo = calloc(size, sizeof (cache_ptr)); 7267c478bd9Sstevel@tonic-gate if (uc->uc_fifo == NULL) { 72761961e0fSrobinson (void) syslog(LOG_ERR, cache_enable_str, alloc_err, "fifo"); 72861961e0fSrobinson free(uc->uc_entries); 72961961e0fSrobinson free(uc); 73061961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 7317c478bd9Sstevel@tonic-gate return (0); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate su->su_cache = (char *)uc; 73461961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 7357c478bd9Sstevel@tonic-gate return (1); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* 7397c478bd9Sstevel@tonic-gate * Set an entry in the cache. It assumes that the uc entry is set from 7407c478bd9Sstevel@tonic-gate * the earlier call to cache_get() for the same procedure. This will always 7417c478bd9Sstevel@tonic-gate * happen because cache_get() is calle by svc_dg_recv and cache_set() is called 7427c478bd9Sstevel@tonic-gate * by svc_dg_reply(). All this hoopla because the right RPC parameters are 7437c478bd9Sstevel@tonic-gate * not available at svc_dg_reply time. 7447c478bd9Sstevel@tonic-gate */ 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate static const char cache_set_str[] = "cache_set: %s"; 7477c478bd9Sstevel@tonic-gate static const char cache_set_err1[] = "victim not found"; 7487c478bd9Sstevel@tonic-gate static const char cache_set_err2[] = "victim alloc failed"; 7497c478bd9Sstevel@tonic-gate static const char cache_set_err3[] = "could not allocate new rpc buffer"; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate static void 75261961e0fSrobinson cache_set(SVCXPRT *xprt, uint32_t replylen) 7537c478bd9Sstevel@tonic-gate { 7547c478bd9Sstevel@tonic-gate SVCXPRT *parent; 7557c478bd9Sstevel@tonic-gate cache_ptr victim; 7567c478bd9Sstevel@tonic-gate cache_ptr *vicp; 7577c478bd9Sstevel@tonic-gate struct svc_dg_data *su; 7587c478bd9Sstevel@tonic-gate struct cl_cache *uc; 7597c478bd9Sstevel@tonic-gate uint_t loc; 7607c478bd9Sstevel@tonic-gate char *newbuf, *newbuf2; 7617c478bd9Sstevel@tonic-gate int my_mallocs = 0; 7627c478bd9Sstevel@tonic-gate #ifdef RPC_CACHE_DEBUG 7637c478bd9Sstevel@tonic-gate struct netconfig *nconf; 7647c478bd9Sstevel@tonic-gate char *uaddr; 7657c478bd9Sstevel@tonic-gate #endif 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7687c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE && SVCEXT(xprt)->parent != NULL) 7697c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7707c478bd9Sstevel@tonic-gate parent = SVCEXT(xprt)->parent; 7717c478bd9Sstevel@tonic-gate else 7727c478bd9Sstevel@tonic-gate parent = xprt; 7737c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 774f48205beScasper su = get_svc_dg_data(xprt); 7757c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 776f48205beScasper uc = (struct cl_cache *)get_svc_dg_data(parent)->su_cache; 7777c478bd9Sstevel@tonic-gate 77861961e0fSrobinson (void) mutex_lock(&dupreq_lock); 7797c478bd9Sstevel@tonic-gate /* 7807c478bd9Sstevel@tonic-gate * Find space for the new entry, either by 7817c478bd9Sstevel@tonic-gate * reusing an old entry, or by mallocing a new one 7827c478bd9Sstevel@tonic-gate */ 7837c478bd9Sstevel@tonic-gate victim = uc->uc_fifo[uc->uc_nextvictim]; 7847c478bd9Sstevel@tonic-gate if (victim != NULL) { 7857c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7867c478bd9Sstevel@tonic-gate loc = CACHE_LOC(parent, victim->cache_xid); 7877c478bd9Sstevel@tonic-gate for (vicp = &uc->uc_entries[loc]; 7887c478bd9Sstevel@tonic-gate *vicp != NULL && *vicp != victim; 7897c478bd9Sstevel@tonic-gate vicp = &(*vicp)->cache_next) 7907c478bd9Sstevel@tonic-gate ; 7917c478bd9Sstevel@tonic-gate if (*vicp == NULL) { 7927c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, cache_set_str, cache_set_err1); 79361961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 7947c478bd9Sstevel@tonic-gate return; 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate *vicp = victim->cache_next; /* remove from cache */ 7977c478bd9Sstevel@tonic-gate newbuf = victim->cache_reply; 7987c478bd9Sstevel@tonic-gate } else { 79961961e0fSrobinson victim = malloc(sizeof (struct cache_node)); 8007c478bd9Sstevel@tonic-gate if (victim == NULL) { 8017c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, cache_set_str, cache_set_err2); 80261961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 8037c478bd9Sstevel@tonic-gate return; 8047c478bd9Sstevel@tonic-gate } 80561961e0fSrobinson newbuf = malloc(su->su_iosz); 8067c478bd9Sstevel@tonic-gate if (newbuf == NULL) { 8077c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, cache_set_str, cache_set_err3); 80861961e0fSrobinson free(victim); 80961961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 8107c478bd9Sstevel@tonic-gate return; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate my_mallocs = 1; 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate /* 8167c478bd9Sstevel@tonic-gate * Store it away 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate #ifdef RPC_CACHE_DEBUG 8197c478bd9Sstevel@tonic-gate if (nconf = getnetconfigent(xprt->xp_netid)) { 8207c478bd9Sstevel@tonic-gate uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); 8217c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 8227c478bd9Sstevel@tonic-gate printf( 8237c478bd9Sstevel@tonic-gate "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n", 8243669bedeSViswanathan Kannappan su->su_xid, uc->uc_prog, uc->uc_vers, uc->uc_proc, uaddr); 8257c478bd9Sstevel@tonic-gate free(uaddr); 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate #endif 82861961e0fSrobinson newbuf2 = malloc(sizeof (char) * xprt->xp_rtaddr.len); 8297c478bd9Sstevel@tonic-gate if (newbuf2 == NULL) { 8307c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "cache_set : out of memory"); 8317c478bd9Sstevel@tonic-gate if (my_mallocs) { 83261961e0fSrobinson free(victim); 83361961e0fSrobinson free(newbuf); 8347c478bd9Sstevel@tonic-gate } 83561961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 8367c478bd9Sstevel@tonic-gate return; 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate victim->cache_replylen = replylen; 8397c478bd9Sstevel@tonic-gate victim->cache_reply = rpc_buffer(xprt); 8407c478bd9Sstevel@tonic-gate rpc_buffer(xprt) = newbuf; 8413669bedeSViswanathan Kannappan xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, 8423669bedeSViswanathan Kannappan XDR_ENCODE); 8437c478bd9Sstevel@tonic-gate su->su_tudata.udata.buf = (char *)rpc_buffer(xprt); 8447c478bd9Sstevel@tonic-gate victim->cache_xid = su->su_xid; 8457c478bd9Sstevel@tonic-gate victim->cache_proc = uc->uc_proc; 8467c478bd9Sstevel@tonic-gate victim->cache_vers = uc->uc_vers; 8477c478bd9Sstevel@tonic-gate victim->cache_prog = uc->uc_prog; 8487c478bd9Sstevel@tonic-gate victim->cache_addr = xprt->xp_rtaddr; 8497c478bd9Sstevel@tonic-gate victim->cache_addr.buf = newbuf2; 8507c478bd9Sstevel@tonic-gate (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf, 8517c478bd9Sstevel@tonic-gate (int)xprt->xp_rtaddr.len); 8527c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8537c478bd9Sstevel@tonic-gate loc = CACHE_LOC(parent, victim->cache_xid); 8547c478bd9Sstevel@tonic-gate victim->cache_next = uc->uc_entries[loc]; 8557c478bd9Sstevel@tonic-gate uc->uc_entries[loc] = victim; 8567c478bd9Sstevel@tonic-gate uc->uc_fifo[uc->uc_nextvictim++] = victim; 8577c478bd9Sstevel@tonic-gate uc->uc_nextvictim %= uc->uc_size; 85861961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * Try to get an entry from the cache 8637c478bd9Sstevel@tonic-gate * return 1 if found, 0 if not found and set the stage for cache_set() 8647c478bd9Sstevel@tonic-gate */ 8657c478bd9Sstevel@tonic-gate static int 86661961e0fSrobinson cache_get(SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, 86761961e0fSrobinson uint32_t *replylenp) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate SVCXPRT *parent; 8707c478bd9Sstevel@tonic-gate uint_t loc; 8717c478bd9Sstevel@tonic-gate cache_ptr ent; 8727c478bd9Sstevel@tonic-gate struct svc_dg_data *su; 8737c478bd9Sstevel@tonic-gate struct cl_cache *uc; 8747c478bd9Sstevel@tonic-gate #ifdef RPC_CACHE_DEBUG 8757c478bd9Sstevel@tonic-gate struct netconfig *nconf; 8767c478bd9Sstevel@tonic-gate char *uaddr; 8777c478bd9Sstevel@tonic-gate #endif 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8807c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE && SVCEXT(xprt)->parent != NULL) 8817c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8827c478bd9Sstevel@tonic-gate parent = SVCEXT(xprt)->parent; 8837c478bd9Sstevel@tonic-gate else 8847c478bd9Sstevel@tonic-gate parent = xprt; 8857c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 886f48205beScasper su = get_svc_dg_data(xprt); 8877c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 888f48205beScasper uc = (struct cl_cache *)get_svc_dg_data(parent)->su_cache; 8897c478bd9Sstevel@tonic-gate 89061961e0fSrobinson (void) mutex_lock(&dupreq_lock); 8917c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8927c478bd9Sstevel@tonic-gate loc = CACHE_LOC(parent, su->su_xid); 8937c478bd9Sstevel@tonic-gate for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { 8947c478bd9Sstevel@tonic-gate if (ent->cache_xid == su->su_xid && 8957c478bd9Sstevel@tonic-gate ent->cache_proc == msg->rm_call.cb_proc && 8967c478bd9Sstevel@tonic-gate ent->cache_vers == msg->rm_call.cb_vers && 8977c478bd9Sstevel@tonic-gate ent->cache_prog == msg->rm_call.cb_prog && 8987c478bd9Sstevel@tonic-gate ent->cache_addr.len == xprt->xp_rtaddr.len && 8997c478bd9Sstevel@tonic-gate (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf, 9007c478bd9Sstevel@tonic-gate xprt->xp_rtaddr.len) == 0)) { 9017c478bd9Sstevel@tonic-gate #ifdef RPC_CACHE_DEBUG 9027c478bd9Sstevel@tonic-gate if (nconf = getnetconfigent(xprt->xp_netid)) { 9037c478bd9Sstevel@tonic-gate uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); 9047c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 9057c478bd9Sstevel@tonic-gate printf( 9067c478bd9Sstevel@tonic-gate "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n", 9077c478bd9Sstevel@tonic-gate su->su_xid, msg->rm_call.cb_prog, 9087c478bd9Sstevel@tonic-gate msg->rm_call.cb_vers, 9097c478bd9Sstevel@tonic-gate msg->rm_call.cb_proc, uaddr); 9107c478bd9Sstevel@tonic-gate free(uaddr); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate #endif 9137c478bd9Sstevel@tonic-gate *replyp = ent->cache_reply; 9147c478bd9Sstevel@tonic-gate *replylenp = ent->cache_replylen; 91561961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 9167c478bd9Sstevel@tonic-gate return (1); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * Failed to find entry 9217c478bd9Sstevel@tonic-gate * Remember a few things so we can do a set later 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate uc->uc_proc = msg->rm_call.cb_proc; 9247c478bd9Sstevel@tonic-gate uc->uc_vers = msg->rm_call.cb_vers; 9257c478bd9Sstevel@tonic-gate uc->uc_prog = msg->rm_call.cb_prog; 92661961e0fSrobinson (void) mutex_unlock(&dupreq_lock); 9277c478bd9Sstevel@tonic-gate return (0); 9287c478bd9Sstevel@tonic-gate } 929