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
svc_dg_xprtfree(SVCXPRT * xprt)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 *
svc_dg_create_private(int fd,uint_t sendsize,uint_t recvsize)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 *
svc_dg_create(const int fd,const uint_t sendsize,const uint_t recvsize)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 *
svc_dg_xprtcopy(SVCXPRT * parent)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
svc_dg_stat(SVCXPRT * xprt)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
extract_cred(const struct netbuf * src,struct netbuf * dest)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
set_src_addr(SVCXPRT * xprt,struct netbuf * opt)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
svc_dg_recv(SVCXPRT * xprt,struct rpc_msg * msg)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
svc_dg_reply(SVCXPRT * xprt,struct rpc_msg * msg)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
svc_dg_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)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
svc_dg_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)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
svc_dg_destroy(SVCXPRT * xprt)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
_svc_dg_destroy_private(SVCXPRT * xprt)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
svc_dg_control(SVCXPRT * xprt,const uint_t rq,void * in)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 *
svc_dg_ops(void)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
svc_dg_enablecache(SVCXPRT * xprt,const uint_t size)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
cache_set(SVCXPRT * xprt,uint32_t replylen)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
cache_get(SVCXPRT * xprt,struct rpc_msg * msg,char ** replyp,uint32_t * replylenp)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