xref: /titanic_52/usr/src/lib/libnsl/rpc/svc_dg.c (revision 09b0d01c5bc323b8ee7043100e09aded27cc12ab)
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