xref: /minix3/lib/libc/rpc/svc.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: svc.c,v 1.34 2013/03/11 20:19:29 tron Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
4*84d9c625SLionel Sambuc  * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras  *
6*84d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
7*84d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions are
8*84d9c625SLionel Sambuc  * met:
92fe8fb19SBen Gras  *
10*84d9c625SLionel Sambuc  *     * Redistributions of source code must retain the above copyright
11*84d9c625SLionel Sambuc  *       notice, this list of conditions and the following disclaimer.
12*84d9c625SLionel Sambuc  *     * Redistributions in binary form must reproduce the above
13*84d9c625SLionel Sambuc  *       copyright notice, this list of conditions and the following
14*84d9c625SLionel Sambuc  *       disclaimer in the documentation and/or other materials
15*84d9c625SLionel Sambuc  *       provided with the distribution.
16*84d9c625SLionel Sambuc  *     * Neither the name of the "Oracle America, Inc." nor the names of its
17*84d9c625SLionel Sambuc  *       contributors may be used to endorse or promote products derived
18*84d9c625SLionel Sambuc  *       from this software without specific prior written permission.
192fe8fb19SBen Gras  *
20*84d9c625SLionel Sambuc  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*84d9c625SLionel Sambuc  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*84d9c625SLionel Sambuc  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*84d9c625SLionel Sambuc  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24*84d9c625SLionel Sambuc  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25*84d9c625SLionel Sambuc  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*84d9c625SLionel Sambuc  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27*84d9c625SLionel Sambuc  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*84d9c625SLionel Sambuc  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29*84d9c625SLionel Sambuc  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30*84d9c625SLionel Sambuc  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*84d9c625SLionel Sambuc  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras  */
332fe8fb19SBen Gras 
342fe8fb19SBen Gras #include <sys/cdefs.h>
352fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
362fe8fb19SBen Gras #if 0
372fe8fb19SBen Gras static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
382fe8fb19SBen Gras static char *sccsid = "@(#)svc.c	2.4 88/08/11 4.0 RPCSRC";
392fe8fb19SBen Gras #else
40*84d9c625SLionel Sambuc __RCSID("$NetBSD: svc.c,v 1.34 2013/03/11 20:19:29 tron Exp $");
412fe8fb19SBen Gras #endif
422fe8fb19SBen Gras #endif
432fe8fb19SBen Gras 
442fe8fb19SBen Gras /*
452fe8fb19SBen Gras  * svc.c, Server-side remote procedure call interface.
462fe8fb19SBen Gras  *
472fe8fb19SBen Gras  * There are two sets of procedures here.  The xprt routines are
482fe8fb19SBen Gras  * for handling transport handles.  The svc routines handle the
492fe8fb19SBen Gras  * list of service routines.
502fe8fb19SBen Gras  *
512fe8fb19SBen Gras  * Copyright (C) 1984, Sun Microsystems, Inc.
522fe8fb19SBen Gras  */
532fe8fb19SBen Gras 
542fe8fb19SBen Gras #include "namespace.h"
552fe8fb19SBen Gras #include "reentrant.h"
562fe8fb19SBen Gras #include <sys/types.h>
572fe8fb19SBen Gras #include <sys/poll.h>
582fe8fb19SBen Gras #include <assert.h>
592fe8fb19SBen Gras #include <errno.h>
602fe8fb19SBen Gras #include <stdlib.h>
612fe8fb19SBen Gras #include <string.h>
622fe8fb19SBen Gras #include <err.h>
632fe8fb19SBen Gras 
642fe8fb19SBen Gras #include <rpc/rpc.h>
652fe8fb19SBen Gras #ifdef PORTMAP
662fe8fb19SBen Gras #include <rpc/pmap_clnt.h>
672fe8fb19SBen Gras #endif
682fe8fb19SBen Gras 
69*84d9c625SLionel Sambuc #include "svc_fdset.h"
702fe8fb19SBen Gras #include "rpc_internal.h"
712fe8fb19SBen Gras 
722fe8fb19SBen Gras #ifdef __weak_alias
732fe8fb19SBen Gras __weak_alias(svc_getreq,_svc_getreq)
742fe8fb19SBen Gras __weak_alias(svc_getreqset,_svc_getreqset)
752fe8fb19SBen Gras __weak_alias(svc_getreq_common,_svc_getreq_common)
762fe8fb19SBen Gras __weak_alias(svc_register,_svc_register)
772fe8fb19SBen Gras __weak_alias(svc_reg,_svc_reg)
782fe8fb19SBen Gras __weak_alias(svc_unreg,_svc_unreg)
792fe8fb19SBen Gras __weak_alias(svc_sendreply,_svc_sendreply)
802fe8fb19SBen Gras __weak_alias(svc_unregister,_svc_unregister)
812fe8fb19SBen Gras __weak_alias(svcerr_auth,_svcerr_auth)
822fe8fb19SBen Gras __weak_alias(svcerr_decode,_svcerr_decode)
832fe8fb19SBen Gras __weak_alias(svcerr_noproc,_svcerr_noproc)
842fe8fb19SBen Gras __weak_alias(svcerr_noprog,_svcerr_noprog)
852fe8fb19SBen Gras __weak_alias(svcerr_progvers,_svcerr_progvers)
862fe8fb19SBen Gras __weak_alias(svcerr_systemerr,_svcerr_systemerr)
872fe8fb19SBen Gras __weak_alias(svcerr_weakauth,_svcerr_weakauth)
882fe8fb19SBen Gras __weak_alias(xprt_register,_xprt_register)
892fe8fb19SBen Gras __weak_alias(xprt_unregister,_xprt_unregister)
902fe8fb19SBen Gras __weak_alias(rpc_control,_rpc_control)
912fe8fb19SBen Gras #endif
922fe8fb19SBen Gras 
932fe8fb19SBen Gras SVCXPRT **__svc_xports;
942fe8fb19SBen Gras int __svc_maxrec;
952fe8fb19SBen Gras 
962fe8fb19SBen Gras #define	RQCRED_SIZE	400		/* this size is excessive */
972fe8fb19SBen Gras 
982fe8fb19SBen Gras #define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
992fe8fb19SBen Gras #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
1002fe8fb19SBen Gras 
1012fe8fb19SBen Gras #define max(a, b) (a > b ? a : b)
1022fe8fb19SBen Gras 
1032fe8fb19SBen Gras /*
1042fe8fb19SBen Gras  * The services list
1052fe8fb19SBen Gras  * Each entry represents a set of procedures (an rpc program).
1062fe8fb19SBen Gras  * The dispatch routine takes request structs and runs the
1072fe8fb19SBen Gras  * apropriate procedure.
1082fe8fb19SBen Gras  */
1092fe8fb19SBen Gras static struct svc_callout {
1102fe8fb19SBen Gras 	struct svc_callout *sc_next;
1112fe8fb19SBen Gras 	rpcprog_t	    sc_prog;
1122fe8fb19SBen Gras 	rpcvers_t	    sc_vers;
1132fe8fb19SBen Gras 	char		   *sc_netid;
114f14fb602SLionel Sambuc 	void		    (*sc_dispatch)(struct svc_req *, SVCXPRT *);
1152fe8fb19SBen Gras } *svc_head;
1162fe8fb19SBen Gras 
1172fe8fb19SBen Gras #ifdef _REENTRANT
1182fe8fb19SBen Gras extern rwlock_t svc_lock;
1192fe8fb19SBen Gras extern rwlock_t svc_fd_lock;
1202fe8fb19SBen Gras #endif
1212fe8fb19SBen Gras 
122f14fb602SLionel Sambuc static struct svc_callout *svc_find(rpcprog_t, rpcvers_t,
123f14fb602SLionel Sambuc 					 struct svc_callout **, char *);
124f14fb602SLionel Sambuc static void __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock);
1252fe8fb19SBen Gras 
1262fe8fb19SBen Gras /* ***************  SVCXPRT related stuff **************** */
1272fe8fb19SBen Gras 
1282fe8fb19SBen Gras /*
1292fe8fb19SBen Gras  * Activate a transport handle.
1302fe8fb19SBen Gras  */
131*84d9c625SLionel Sambuc bool_t
xprt_register(SVCXPRT * xprt)132f14fb602SLionel Sambuc xprt_register(SVCXPRT *xprt)
1332fe8fb19SBen Gras {
1342fe8fb19SBen Gras 	int sock;
1352fe8fb19SBen Gras 
1362fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
1372fe8fb19SBen Gras 
1382fe8fb19SBen Gras 	sock = xprt->xp_fd;
1392fe8fb19SBen Gras 
1402fe8fb19SBen Gras 	rwlock_wrlock(&svc_fd_lock);
1412fe8fb19SBen Gras 	if (__svc_xports == NULL) {
1422fe8fb19SBen Gras 		__svc_xports = mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
1432fe8fb19SBen Gras 		if (__svc_xports == NULL) {
144*84d9c625SLionel Sambuc 			warn("%s: out of memory", __func__);
1452fe8fb19SBen Gras 			goto out;
1462fe8fb19SBen Gras 		}
1472fe8fb19SBen Gras 		memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
1482fe8fb19SBen Gras 	}
149*84d9c625SLionel Sambuc 	if (sock >= FD_SETSIZE) {
150*84d9c625SLionel Sambuc 		warnx("%s: socket descriptor %d too large for setsize %u",
151*84d9c625SLionel Sambuc 		    __func__, sock, (unsigned)FD_SETSIZE);
152*84d9c625SLionel Sambuc 		goto out;
1532fe8fb19SBen Gras 	}
154*84d9c625SLionel Sambuc 	__svc_xports[sock] = xprt;
155*84d9c625SLionel Sambuc 	FD_SET(sock, get_fdset());
156*84d9c625SLionel Sambuc 	*get_fdsetmax() = max(*get_fdsetmax(), sock);
157*84d9c625SLionel Sambuc 	rwlock_unlock(&svc_fd_lock);
158*84d9c625SLionel Sambuc 	return (TRUE);
159*84d9c625SLionel Sambuc 
1602fe8fb19SBen Gras out:
1612fe8fb19SBen Gras 	rwlock_unlock(&svc_fd_lock);
162*84d9c625SLionel Sambuc 	return (FALSE);
1632fe8fb19SBen Gras }
1642fe8fb19SBen Gras 
1652fe8fb19SBen Gras void
xprt_unregister(SVCXPRT * xprt)1662fe8fb19SBen Gras xprt_unregister(SVCXPRT *xprt)
1672fe8fb19SBen Gras {
1682fe8fb19SBen Gras 	__xprt_do_unregister(xprt, TRUE);
1692fe8fb19SBen Gras }
1702fe8fb19SBen Gras 
1712fe8fb19SBen Gras void
__xprt_unregister_unlocked(SVCXPRT * xprt)1722fe8fb19SBen Gras __xprt_unregister_unlocked(SVCXPRT *xprt)
1732fe8fb19SBen Gras {
1742fe8fb19SBen Gras 	__xprt_do_unregister(xprt, FALSE);
1752fe8fb19SBen Gras }
1762fe8fb19SBen Gras 
1772fe8fb19SBen Gras /*
1782fe8fb19SBen Gras  * De-activate a transport handle.
1792fe8fb19SBen Gras  */
1802fe8fb19SBen Gras static void
__xprt_do_unregister(SVCXPRT * xprt,bool_t dolock)181f14fb602SLionel Sambuc __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
1822fe8fb19SBen Gras {
1832fe8fb19SBen Gras 	int sock;
1842fe8fb19SBen Gras 
1852fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
1862fe8fb19SBen Gras 
1872fe8fb19SBen Gras 	sock = xprt->xp_fd;
1882fe8fb19SBen Gras 
1892fe8fb19SBen Gras 	if (dolock)
1902fe8fb19SBen Gras 		rwlock_wrlock(&svc_fd_lock);
1912fe8fb19SBen Gras 	if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
1922fe8fb19SBen Gras 		__svc_xports[sock] = NULL;
193*84d9c625SLionel Sambuc 		FD_CLR(sock, get_fdset());
194*84d9c625SLionel Sambuc 		if (sock >= *get_fdsetmax()) {
195*84d9c625SLionel Sambuc 			for ((*get_fdsetmax())--; *get_fdsetmax() >= 0;
196*84d9c625SLionel Sambuc 			    (*get_fdsetmax())--)
197*84d9c625SLionel Sambuc 				if (__svc_xports[*get_fdsetmax()])
1982fe8fb19SBen Gras 					break;
1992fe8fb19SBen Gras 		}
2002fe8fb19SBen Gras 	}
2012fe8fb19SBen Gras 	if (dolock)
2022fe8fb19SBen Gras 		rwlock_unlock(&svc_fd_lock);
2032fe8fb19SBen Gras }
2042fe8fb19SBen Gras 
2052fe8fb19SBen Gras /*
2062fe8fb19SBen Gras  * Add a service program to the callout list.
2072fe8fb19SBen Gras  * The dispatch routine will be called when a rpc request for this
2082fe8fb19SBen Gras  * program number comes in.
2092fe8fb19SBen Gras  */
2102fe8fb19SBen Gras bool_t
svc_reg(SVCXPRT * xprt,const rpcprog_t prog,const rpcvers_t vers,void (* dispatch)(struct svc_req *,SVCXPRT *),const struct netconfig * nconf)211f14fb602SLionel Sambuc svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
212f14fb602SLionel Sambuc 	void (*dispatch)(struct svc_req *, SVCXPRT *),
213f14fb602SLionel Sambuc 	const struct netconfig *nconf)
2142fe8fb19SBen Gras {
2152fe8fb19SBen Gras 	bool_t dummy;
2162fe8fb19SBen Gras 	struct svc_callout *prev;
2172fe8fb19SBen Gras 	struct svc_callout *s;
2182fe8fb19SBen Gras 	struct netconfig *tnconf;
2192fe8fb19SBen Gras 	char *netid = NULL;
2202fe8fb19SBen Gras 	int flag = 0;
2212fe8fb19SBen Gras 
2222fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
2232fe8fb19SBen Gras 	/* XXX: dispatch may be NULL ??? */
2242fe8fb19SBen Gras 
2252fe8fb19SBen Gras /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
2262fe8fb19SBen Gras 
2272fe8fb19SBen Gras 	if (xprt->xp_netid) {
2282fe8fb19SBen Gras 		netid = strdup(xprt->xp_netid);
2292fe8fb19SBen Gras 		flag = 1;
2302fe8fb19SBen Gras 	} else if (nconf && nconf->nc_netid) {
2312fe8fb19SBen Gras 		netid = strdup(nconf->nc_netid);
2322fe8fb19SBen Gras 		flag = 1;
2332fe8fb19SBen Gras 	} else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
2342fe8fb19SBen Gras 		netid = strdup(tnconf->nc_netid);
2352fe8fb19SBen Gras 		flag = 1;
2362fe8fb19SBen Gras 		freenetconfigent(tnconf);
2372fe8fb19SBen Gras 	} /* must have been created with svc_raw_create */
2382fe8fb19SBen Gras 	if ((netid == NULL) && (flag == 1)) {
2392fe8fb19SBen Gras 		return (FALSE);
2402fe8fb19SBen Gras 	}
2412fe8fb19SBen Gras 
2422fe8fb19SBen Gras 	rwlock_wrlock(&svc_lock);
2432fe8fb19SBen Gras 	if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
2442fe8fb19SBen Gras 		if (netid)
2452fe8fb19SBen Gras 			free(netid);
2462fe8fb19SBen Gras 		if (s->sc_dispatch == dispatch)
2472fe8fb19SBen Gras 			goto rpcb_it; /* he is registering another xptr */
2482fe8fb19SBen Gras 		rwlock_unlock(&svc_lock);
2492fe8fb19SBen Gras 		return (FALSE);
2502fe8fb19SBen Gras 	}
2512fe8fb19SBen Gras 	s = mem_alloc(sizeof (struct svc_callout));
2522fe8fb19SBen Gras 	if (s == NULL) {
2532fe8fb19SBen Gras 		if (netid)
2542fe8fb19SBen Gras 			free(netid);
2552fe8fb19SBen Gras 		rwlock_unlock(&svc_lock);
2562fe8fb19SBen Gras 		return (FALSE);
2572fe8fb19SBen Gras 	}
2582fe8fb19SBen Gras 
2592fe8fb19SBen Gras 	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
2602fe8fb19SBen Gras 		if ((((SVCXPRT *) xprt)->xp_netid = strdup(netid)) == NULL) {
2612fe8fb19SBen Gras 			warn("svc_reg");
2622fe8fb19SBen Gras 			mem_free(s, sizeof(struct svc_callout));
2632fe8fb19SBen Gras 			rwlock_unlock(&svc_lock);
2642fe8fb19SBen Gras 			return FALSE;
2652fe8fb19SBen Gras 		}
2662fe8fb19SBen Gras 
2672fe8fb19SBen Gras 	s->sc_prog = prog;
2682fe8fb19SBen Gras 	s->sc_vers = vers;
2692fe8fb19SBen Gras 	s->sc_dispatch = dispatch;
2702fe8fb19SBen Gras 	s->sc_netid = netid;
2712fe8fb19SBen Gras 	s->sc_next = svc_head;
2722fe8fb19SBen Gras 	svc_head = s;
2732fe8fb19SBen Gras 
2742fe8fb19SBen Gras rpcb_it:
2752fe8fb19SBen Gras 	rwlock_unlock(&svc_lock);
2762fe8fb19SBen Gras 	/* now register the information with the local binder service */
2772fe8fb19SBen Gras 	if (nconf) {
2782fe8fb19SBen Gras 		dummy = rpcb_set(prog, vers, __UNCONST(nconf),
2792fe8fb19SBen Gras 		&((SVCXPRT *) xprt)->xp_ltaddr);
2802fe8fb19SBen Gras 		return (dummy);
2812fe8fb19SBen Gras 	}
2822fe8fb19SBen Gras 	return (TRUE);
2832fe8fb19SBen Gras }
2842fe8fb19SBen Gras 
2852fe8fb19SBen Gras /*
2862fe8fb19SBen Gras  * Remove a service program from the callout list.
2872fe8fb19SBen Gras  */
2882fe8fb19SBen Gras void
svc_unreg(const rpcprog_t prog,const rpcvers_t vers)289f14fb602SLionel Sambuc svc_unreg(const rpcprog_t prog, const rpcvers_t vers)
2902fe8fb19SBen Gras {
2912fe8fb19SBen Gras 	struct svc_callout *prev;
2922fe8fb19SBen Gras 	struct svc_callout *s;
2932fe8fb19SBen Gras 
2942fe8fb19SBen Gras 	/* unregister the information anyway */
2952fe8fb19SBen Gras 	(void) rpcb_unset(prog, vers, NULL);
2962fe8fb19SBen Gras 	rwlock_wrlock(&svc_lock);
2972fe8fb19SBen Gras 	while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
2982fe8fb19SBen Gras 		if (prev == NULL) {
2992fe8fb19SBen Gras 			svc_head = s->sc_next;
3002fe8fb19SBen Gras 		} else {
3012fe8fb19SBen Gras 			prev->sc_next = s->sc_next;
3022fe8fb19SBen Gras 		}
3032fe8fb19SBen Gras 		s->sc_next = NULL;
3042fe8fb19SBen Gras 		if (s->sc_netid)
3052fe8fb19SBen Gras 			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
3062fe8fb19SBen Gras 		mem_free(s, sizeof (struct svc_callout));
3072fe8fb19SBen Gras 	}
3082fe8fb19SBen Gras 	rwlock_unlock(&svc_lock);
3092fe8fb19SBen Gras }
3102fe8fb19SBen Gras 
3112fe8fb19SBen Gras /* ********************** CALLOUT list related stuff ************* */
3122fe8fb19SBen Gras 
3132fe8fb19SBen Gras #ifdef PORTMAP
3142fe8fb19SBen Gras /*
3152fe8fb19SBen Gras  * Add a service program to the callout list.
3162fe8fb19SBen Gras  * The dispatch routine will be called when a rpc request for this
3172fe8fb19SBen Gras  * program number comes in.
3182fe8fb19SBen Gras  */
3192fe8fb19SBen Gras bool_t
svc_register(SVCXPRT * xprt,u_long prog,u_long vers,void (* dispatch)(struct svc_req *,SVCXPRT *),int protocol)320f14fb602SLionel Sambuc svc_register(SVCXPRT *xprt, u_long prog, u_long vers,
321f14fb602SLionel Sambuc 	void (*dispatch)(struct svc_req *, SVCXPRT *), int protocol)
3222fe8fb19SBen Gras {
3232fe8fb19SBen Gras 	struct svc_callout *prev;
3242fe8fb19SBen Gras 	struct svc_callout *s;
3252fe8fb19SBen Gras 
3262fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
3272fe8fb19SBen Gras 	_DIAGASSERT(dispatch != NULL);
3282fe8fb19SBen Gras 
3292fe8fb19SBen Gras 	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
3302fe8fb19SBen Gras 	    NULL) {
3312fe8fb19SBen Gras 		if (s->sc_dispatch == dispatch)
3322fe8fb19SBen Gras 			goto pmap_it;  /* he is registering another xptr */
3332fe8fb19SBen Gras 		return (FALSE);
3342fe8fb19SBen Gras 	}
3352fe8fb19SBen Gras 	s = mem_alloc(sizeof(struct svc_callout));
3362fe8fb19SBen Gras 	if (s == NULL) {
3372fe8fb19SBen Gras 		return (FALSE);
3382fe8fb19SBen Gras 	}
3392fe8fb19SBen Gras 	s->sc_prog = (rpcprog_t)prog;
3402fe8fb19SBen Gras 	s->sc_vers = (rpcvers_t)vers;
3412fe8fb19SBen Gras 	s->sc_dispatch = dispatch;
3422fe8fb19SBen Gras 	s->sc_next = svc_head;
3432fe8fb19SBen Gras 	svc_head = s;
3442fe8fb19SBen Gras pmap_it:
3452fe8fb19SBen Gras 	/* now register the information with the local binder service */
3462fe8fb19SBen Gras 	if (protocol) {
3472fe8fb19SBen Gras 		return (pmap_set(prog, vers, protocol, xprt->xp_port));
3482fe8fb19SBen Gras 	}
3492fe8fb19SBen Gras 	return (TRUE);
3502fe8fb19SBen Gras }
3512fe8fb19SBen Gras 
3522fe8fb19SBen Gras /*
3532fe8fb19SBen Gras  * Remove a service program from the callout list.
3542fe8fb19SBen Gras  */
3552fe8fb19SBen Gras void
svc_unregister(u_long prog,u_long vers)356f14fb602SLionel Sambuc svc_unregister(u_long prog, u_long vers)
3572fe8fb19SBen Gras {
3582fe8fb19SBen Gras 	struct svc_callout *prev;
3592fe8fb19SBen Gras 	struct svc_callout *s;
3602fe8fb19SBen Gras 
3612fe8fb19SBen Gras 	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
3622fe8fb19SBen Gras 	    NULL)
3632fe8fb19SBen Gras 		return;
3642fe8fb19SBen Gras 	if (prev == NULL) {
3652fe8fb19SBen Gras 		svc_head = s->sc_next;
3662fe8fb19SBen Gras 	} else {
3672fe8fb19SBen Gras 		prev->sc_next = s->sc_next;
3682fe8fb19SBen Gras 	}
3692fe8fb19SBen Gras 	s->sc_next = NULL;
3702fe8fb19SBen Gras 	mem_free(s, sizeof(struct svc_callout));
3712fe8fb19SBen Gras 	/* now unregister the information with the local binder service */
3722fe8fb19SBen Gras 	(void)pmap_unset(prog, vers);
3732fe8fb19SBen Gras }
3742fe8fb19SBen Gras #endif /* PORTMAP */
3752fe8fb19SBen Gras 
3762fe8fb19SBen Gras /*
3772fe8fb19SBen Gras  * Search the callout list for a program number, return the callout
3782fe8fb19SBen Gras  * struct.
3792fe8fb19SBen Gras  */
3802fe8fb19SBen Gras static struct svc_callout *
svc_find(rpcprog_t prog,rpcvers_t vers,struct svc_callout ** prev,char * netid)381f14fb602SLionel Sambuc svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev, char *netid)
3822fe8fb19SBen Gras {
3832fe8fb19SBen Gras 	struct svc_callout *s, *p;
3842fe8fb19SBen Gras 
3852fe8fb19SBen Gras 	_DIAGASSERT(prev != NULL);
3862fe8fb19SBen Gras 	/* netid is handled below */
3872fe8fb19SBen Gras 
3882fe8fb19SBen Gras 	p = NULL;
3892fe8fb19SBen Gras 	for (s = svc_head; s != NULL; s = s->sc_next) {
3902fe8fb19SBen Gras 		if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
3912fe8fb19SBen Gras 		    ((netid == NULL) || (s->sc_netid == NULL) ||
3922fe8fb19SBen Gras 		    (strcmp(netid, s->sc_netid) == 0)))
3932fe8fb19SBen Gras 			break;
3942fe8fb19SBen Gras 		p = s;
3952fe8fb19SBen Gras 	}
3962fe8fb19SBen Gras 	*prev = p;
3972fe8fb19SBen Gras 	return (s);
3982fe8fb19SBen Gras }
3992fe8fb19SBen Gras 
4002fe8fb19SBen Gras /* ******************* REPLY GENERATION ROUTINES  ************ */
4012fe8fb19SBen Gras 
4022fe8fb19SBen Gras /*
4032fe8fb19SBen Gras  * Send a reply to an rpc request
4042fe8fb19SBen Gras  */
4052fe8fb19SBen Gras bool_t
svc_sendreply(SVCXPRT * xprt,xdrproc_t xdr_results,const char * xdr_location)406f14fb602SLionel Sambuc svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, const char *xdr_location)
4072fe8fb19SBen Gras {
4082fe8fb19SBen Gras 	struct rpc_msg rply;
4092fe8fb19SBen Gras 
4102fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
4112fe8fb19SBen Gras 
4122fe8fb19SBen Gras 	rply.rm_direction = REPLY;
4132fe8fb19SBen Gras 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4142fe8fb19SBen Gras 	rply.acpted_rply.ar_verf = xprt->xp_verf;
4152fe8fb19SBen Gras 	rply.acpted_rply.ar_stat = SUCCESS;
4162fe8fb19SBen Gras 	rply.acpted_rply.ar_results.where = xdr_location;
4172fe8fb19SBen Gras 	rply.acpted_rply.ar_results.proc = xdr_results;
4182fe8fb19SBen Gras 	return (SVC_REPLY(xprt, &rply));
4192fe8fb19SBen Gras }
4202fe8fb19SBen Gras 
4212fe8fb19SBen Gras /*
4222fe8fb19SBen Gras  * No procedure error reply
4232fe8fb19SBen Gras  */
4242fe8fb19SBen Gras void
svcerr_noproc(SVCXPRT * xprt)425f14fb602SLionel Sambuc svcerr_noproc(SVCXPRT *xprt)
4262fe8fb19SBen Gras {
4272fe8fb19SBen Gras 	struct rpc_msg rply;
4282fe8fb19SBen Gras 
4292fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
4302fe8fb19SBen Gras 
4312fe8fb19SBen Gras 	rply.rm_direction = REPLY;
4322fe8fb19SBen Gras 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4332fe8fb19SBen Gras 	rply.acpted_rply.ar_verf = xprt->xp_verf;
4342fe8fb19SBen Gras 	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
4352fe8fb19SBen Gras 	SVC_REPLY(xprt, &rply);
4362fe8fb19SBen Gras }
4372fe8fb19SBen Gras 
4382fe8fb19SBen Gras /*
4392fe8fb19SBen Gras  * Can't decode args error reply
4402fe8fb19SBen Gras  */
4412fe8fb19SBen Gras void
svcerr_decode(SVCXPRT * xprt)442f14fb602SLionel Sambuc svcerr_decode(SVCXPRT *xprt)
4432fe8fb19SBen Gras {
4442fe8fb19SBen Gras 	struct rpc_msg rply;
4452fe8fb19SBen Gras 
4462fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
4472fe8fb19SBen Gras 
4482fe8fb19SBen Gras 	rply.rm_direction = REPLY;
4492fe8fb19SBen Gras 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4502fe8fb19SBen Gras 	rply.acpted_rply.ar_verf = xprt->xp_verf;
4512fe8fb19SBen Gras 	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
4522fe8fb19SBen Gras 	SVC_REPLY(xprt, &rply);
4532fe8fb19SBen Gras }
4542fe8fb19SBen Gras 
4552fe8fb19SBen Gras /*
4562fe8fb19SBen Gras  * Some system error
4572fe8fb19SBen Gras  */
4582fe8fb19SBen Gras void
svcerr_systemerr(SVCXPRT * xprt)459f14fb602SLionel Sambuc svcerr_systemerr(SVCXPRT *xprt)
4602fe8fb19SBen Gras {
4612fe8fb19SBen Gras 	struct rpc_msg rply;
4622fe8fb19SBen Gras 
4632fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
4642fe8fb19SBen Gras 
4652fe8fb19SBen Gras 	rply.rm_direction = REPLY;
4662fe8fb19SBen Gras 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4672fe8fb19SBen Gras 	rply.acpted_rply.ar_verf = xprt->xp_verf;
4682fe8fb19SBen Gras 	rply.acpted_rply.ar_stat = SYSTEM_ERR;
4692fe8fb19SBen Gras 	SVC_REPLY(xprt, &rply);
4702fe8fb19SBen Gras }
4712fe8fb19SBen Gras 
4722fe8fb19SBen Gras #if 0
4732fe8fb19SBen Gras /*
4742fe8fb19SBen Gras  * Tell RPC package to not complain about version errors to the client.	 This
4752fe8fb19SBen Gras  * is useful when revving broadcast protocols that sit on a fixed address.
4762fe8fb19SBen Gras  * There is really one (or should be only one) example of this kind of
4772fe8fb19SBen Gras  * protocol: the portmapper (or rpc binder).
4782fe8fb19SBen Gras  */
4792fe8fb19SBen Gras void
480f14fb602SLionel Sambuc __svc_versquiet_on(SVCXPRT *xprt)
4812fe8fb19SBen Gras {
4822fe8fb19SBen Gras 	u_long	tmp;
4832fe8fb19SBen Gras 
4842fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
4852fe8fb19SBen Gras 
4862fe8fb19SBen Gras 	tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
4872fe8fb19SBen Gras 	xprt->xp_p3 = (caddr_t) tmp;
4882fe8fb19SBen Gras }
4892fe8fb19SBen Gras 
4902fe8fb19SBen Gras void
491f14fb602SLionel Sambuc __svc_versquiet_off(SVCXPRT *xprt)
4922fe8fb19SBen Gras {
4932fe8fb19SBen Gras 	u_long	tmp;
4942fe8fb19SBen Gras 
4952fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
4962fe8fb19SBen Gras 
4972fe8fb19SBen Gras 	tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
4982fe8fb19SBen Gras 	xprt->xp_p3 = (caddr_t) tmp;
4992fe8fb19SBen Gras }
5002fe8fb19SBen Gras 
5012fe8fb19SBen Gras void
502f14fb602SLionel Sambuc svc_versquiet(SVCXPRT *xprt)
5032fe8fb19SBen Gras {
5042fe8fb19SBen Gras 	__svc_versquiet_on(xprt);
5052fe8fb19SBen Gras }
5062fe8fb19SBen Gras 
5072fe8fb19SBen Gras int
508f14fb602SLionel Sambuc __svc_versquiet_get(SVCXPRT *xprt)
5092fe8fb19SBen Gras {
5102fe8fb19SBen Gras 
5112fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
5122fe8fb19SBen Gras 
5132fe8fb19SBen Gras 	return ((int) xprt->xp_p3) & SVC_VERSQUIET;
5142fe8fb19SBen Gras }
5152fe8fb19SBen Gras #endif
5162fe8fb19SBen Gras 
5172fe8fb19SBen Gras /*
5182fe8fb19SBen Gras  * Authentication error reply
5192fe8fb19SBen Gras  */
5202fe8fb19SBen Gras void
svcerr_auth(SVCXPRT * xprt,enum auth_stat why)521f14fb602SLionel Sambuc svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
5222fe8fb19SBen Gras {
5232fe8fb19SBen Gras 	struct rpc_msg rply;
5242fe8fb19SBen Gras 
5252fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
5262fe8fb19SBen Gras 
5272fe8fb19SBen Gras 	rply.rm_direction = REPLY;
5282fe8fb19SBen Gras 	rply.rm_reply.rp_stat = MSG_DENIED;
5292fe8fb19SBen Gras 	rply.rjcted_rply.rj_stat = AUTH_ERROR;
5302fe8fb19SBen Gras 	rply.rjcted_rply.rj_why = why;
5312fe8fb19SBen Gras 	SVC_REPLY(xprt, &rply);
5322fe8fb19SBen Gras }
5332fe8fb19SBen Gras 
5342fe8fb19SBen Gras /*
5352fe8fb19SBen Gras  * Auth too weak error reply
5362fe8fb19SBen Gras  */
5372fe8fb19SBen Gras void
svcerr_weakauth(SVCXPRT * xprt)538f14fb602SLionel Sambuc svcerr_weakauth(SVCXPRT *xprt)
5392fe8fb19SBen Gras {
5402fe8fb19SBen Gras 
5412fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
5422fe8fb19SBen Gras 
5432fe8fb19SBen Gras 	svcerr_auth(xprt, AUTH_TOOWEAK);
5442fe8fb19SBen Gras }
5452fe8fb19SBen Gras 
5462fe8fb19SBen Gras /*
5472fe8fb19SBen Gras  * Program unavailable error reply
5482fe8fb19SBen Gras  */
5492fe8fb19SBen Gras void
svcerr_noprog(SVCXPRT * xprt)550f14fb602SLionel Sambuc svcerr_noprog(SVCXPRT *xprt)
5512fe8fb19SBen Gras {
5522fe8fb19SBen Gras 	struct rpc_msg rply;
5532fe8fb19SBen Gras 
5542fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
5552fe8fb19SBen Gras 
5562fe8fb19SBen Gras 	rply.rm_direction = REPLY;
5572fe8fb19SBen Gras 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
5582fe8fb19SBen Gras 	rply.acpted_rply.ar_verf = xprt->xp_verf;
5592fe8fb19SBen Gras 	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
5602fe8fb19SBen Gras 	SVC_REPLY(xprt, &rply);
5612fe8fb19SBen Gras }
5622fe8fb19SBen Gras 
5632fe8fb19SBen Gras /*
5642fe8fb19SBen Gras  * Program version mismatch error reply
5652fe8fb19SBen Gras  */
5662fe8fb19SBen Gras void
svcerr_progvers(SVCXPRT * xprt,rpcvers_t low_vers,rpcvers_t high_vers)567f14fb602SLionel Sambuc svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
5682fe8fb19SBen Gras {
5692fe8fb19SBen Gras 	struct rpc_msg rply;
5702fe8fb19SBen Gras 
5712fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
5722fe8fb19SBen Gras 
5732fe8fb19SBen Gras 	rply.rm_direction = REPLY;
5742fe8fb19SBen Gras 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
5752fe8fb19SBen Gras 	rply.acpted_rply.ar_verf = xprt->xp_verf;
5762fe8fb19SBen Gras 	rply.acpted_rply.ar_stat = PROG_MISMATCH;
5772fe8fb19SBen Gras 	rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
5782fe8fb19SBen Gras 	rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
5792fe8fb19SBen Gras 	SVC_REPLY(xprt, &rply);
5802fe8fb19SBen Gras }
5812fe8fb19SBen Gras 
5822fe8fb19SBen Gras /* ******************* SERVER INPUT STUFF ******************* */
5832fe8fb19SBen Gras 
5842fe8fb19SBen Gras /*
5852fe8fb19SBen Gras  * Get server side input from some transport.
5862fe8fb19SBen Gras  *
5872fe8fb19SBen Gras  * Statement of authentication parameters management:
5882fe8fb19SBen Gras  * This function owns and manages all authentication parameters, specifically
5892fe8fb19SBen Gras  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
5902fe8fb19SBen Gras  * the "cooked" credentials (rqst->rq_clntcred).
5912fe8fb19SBen Gras  * However, this function does not know the structure of the cooked
5922fe8fb19SBen Gras  * credentials, so it make the following assumptions:
5932fe8fb19SBen Gras  *   a) the structure is contiguous (no pointers), and
5942fe8fb19SBen Gras  *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
5952fe8fb19SBen Gras  * In all events, all three parameters are freed upon exit from this routine.
5962fe8fb19SBen Gras  * The storage is trivially management on the call stack in user land, but
5972fe8fb19SBen Gras  * is mallocated in kernel land.
5982fe8fb19SBen Gras  */
5992fe8fb19SBen Gras 
6002fe8fb19SBen Gras void
svc_getreq(int rdfds)601f14fb602SLionel Sambuc svc_getreq(int rdfds)
6022fe8fb19SBen Gras {
6032fe8fb19SBen Gras 	fd_set readfds;
6042fe8fb19SBen Gras 
6052fe8fb19SBen Gras 	FD_ZERO(&readfds);
6062fe8fb19SBen Gras 	readfds.fds_bits[0] = (unsigned int)rdfds;
6072fe8fb19SBen Gras 	svc_getreqset(&readfds);
6082fe8fb19SBen Gras }
6092fe8fb19SBen Gras 
6102fe8fb19SBen Gras void
svc_getreqset(fd_set * readfds)611f14fb602SLionel Sambuc svc_getreqset(fd_set *readfds)
6122fe8fb19SBen Gras {
6132fe8fb19SBen Gras 	uint32_t mask, *maskp;
6142fe8fb19SBen Gras 	int sock, bit, fd;
6152fe8fb19SBen Gras 
6162fe8fb19SBen Gras 	_DIAGASSERT(readfds != NULL);
6172fe8fb19SBen Gras 
6182fe8fb19SBen Gras 	maskp = readfds->fds_bits;
6192fe8fb19SBen Gras 	for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
6202fe8fb19SBen Gras 	    for (mask = *maskp++; (bit = ffs((int)mask)) != 0;
6212fe8fb19SBen Gras 		mask ^= (1 << (bit - 1))) {
6222fe8fb19SBen Gras 		/* sock has input waiting */
6232fe8fb19SBen Gras 		fd = sock + bit - 1;
6242fe8fb19SBen Gras 		svc_getreq_common(fd);
6252fe8fb19SBen Gras 	    }
6262fe8fb19SBen Gras 	}
6272fe8fb19SBen Gras }
6282fe8fb19SBen Gras 
6292fe8fb19SBen Gras void
svc_getreq_common(int fd)630f14fb602SLionel Sambuc svc_getreq_common(int fd)
6312fe8fb19SBen Gras {
6322fe8fb19SBen Gras 	SVCXPRT *xprt;
6332fe8fb19SBen Gras 	struct svc_req r;
6342fe8fb19SBen Gras 	struct rpc_msg msg;
6352fe8fb19SBen Gras 	int prog_found;
6362fe8fb19SBen Gras 	rpcvers_t low_vers;
6372fe8fb19SBen Gras 	rpcvers_t high_vers;
6382fe8fb19SBen Gras 	enum xprt_stat stat;
6392fe8fb19SBen Gras 	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
6402fe8fb19SBen Gras 
6412fe8fb19SBen Gras 	msg.rm_call.cb_cred.oa_base = cred_area;
6422fe8fb19SBen Gras 	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
6432fe8fb19SBen Gras 	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
6442fe8fb19SBen Gras 
6452fe8fb19SBen Gras 	rwlock_rdlock(&svc_fd_lock);
6462fe8fb19SBen Gras 	xprt = __svc_xports[fd];
6472fe8fb19SBen Gras 	rwlock_unlock(&svc_fd_lock);
6482fe8fb19SBen Gras 	if (xprt == NULL)
6492fe8fb19SBen Gras 		/* But do we control sock? */
6502fe8fb19SBen Gras 		return;
6512fe8fb19SBen Gras 	/* now receive msgs from xprtprt (support batch calls) */
6522fe8fb19SBen Gras 	do {
6532fe8fb19SBen Gras 		if (SVC_RECV(xprt, &msg)) {
6542fe8fb19SBen Gras 
6552fe8fb19SBen Gras 			/* now find the exported program and call it */
6562fe8fb19SBen Gras 			struct svc_callout *s;
6572fe8fb19SBen Gras 			enum auth_stat why;
6582fe8fb19SBen Gras 
6592fe8fb19SBen Gras 			r.rq_xprt = xprt;
6602fe8fb19SBen Gras 			r.rq_prog = msg.rm_call.cb_prog;
6612fe8fb19SBen Gras 			r.rq_vers = msg.rm_call.cb_vers;
6622fe8fb19SBen Gras 			r.rq_proc = msg.rm_call.cb_proc;
6632fe8fb19SBen Gras 			r.rq_cred = msg.rm_call.cb_cred;
6642fe8fb19SBen Gras 			/* first authenticate the message */
6652fe8fb19SBen Gras 			if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
6662fe8fb19SBen Gras 				svcerr_auth(xprt, why);
6672fe8fb19SBen Gras 				goto call_done;
6682fe8fb19SBen Gras 			}
6692fe8fb19SBen Gras 			/* now match message with a registered service*/
6702fe8fb19SBen Gras 			prog_found = FALSE;
6712fe8fb19SBen Gras 			low_vers = (rpcvers_t) -1L;
6722fe8fb19SBen Gras 			high_vers = (rpcvers_t) 0L;
6732fe8fb19SBen Gras 			for (s = svc_head; s != NULL; s = s->sc_next) {
6742fe8fb19SBen Gras 				if (s->sc_prog == r.rq_prog) {
6752fe8fb19SBen Gras 					if (s->sc_vers == r.rq_vers) {
6762fe8fb19SBen Gras 						(*s->sc_dispatch)(&r, xprt);
6772fe8fb19SBen Gras 						goto call_done;
6782fe8fb19SBen Gras 					}  /* found correct version */
6792fe8fb19SBen Gras 					prog_found = TRUE;
6802fe8fb19SBen Gras 					if (s->sc_vers < low_vers)
6812fe8fb19SBen Gras 						low_vers = s->sc_vers;
6822fe8fb19SBen Gras 					if (s->sc_vers > high_vers)
6832fe8fb19SBen Gras 						high_vers = s->sc_vers;
6842fe8fb19SBen Gras 				}   /* found correct program */
6852fe8fb19SBen Gras 			}
6862fe8fb19SBen Gras 			/*
6872fe8fb19SBen Gras 			 * if we got here, the program or version
6882fe8fb19SBen Gras 			 * is not served ...
6892fe8fb19SBen Gras 			 */
6902fe8fb19SBen Gras 			if (prog_found)
6912fe8fb19SBen Gras 				svcerr_progvers(xprt, low_vers, high_vers);
6922fe8fb19SBen Gras 			else
6932fe8fb19SBen Gras 				 svcerr_noprog(xprt);
6942fe8fb19SBen Gras 			/* Fall through to ... */
6952fe8fb19SBen Gras 		}
6962fe8fb19SBen Gras 		/*
6972fe8fb19SBen Gras 		 * Check if the xprt has been disconnected in a
6982fe8fb19SBen Gras 		 * recursive call in the service dispatch routine.
6992fe8fb19SBen Gras 		 * If so, then break.
7002fe8fb19SBen Gras 		 */
7012fe8fb19SBen Gras 		rwlock_rdlock(&svc_fd_lock);
7022fe8fb19SBen Gras 		if (xprt != __svc_xports[fd]) {
7032fe8fb19SBen Gras 			rwlock_unlock(&svc_fd_lock);
7042fe8fb19SBen Gras 			break;
7052fe8fb19SBen Gras 		}
7062fe8fb19SBen Gras 		rwlock_unlock(&svc_fd_lock);
7072fe8fb19SBen Gras call_done:
7082fe8fb19SBen Gras 		if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
7092fe8fb19SBen Gras 			SVC_DESTROY(xprt);
7102fe8fb19SBen Gras 			break;
7112fe8fb19SBen Gras 		}
7122fe8fb19SBen Gras 	} while (stat == XPRT_MOREREQS);
7132fe8fb19SBen Gras }
7142fe8fb19SBen Gras 
7152fe8fb19SBen Gras 
7162fe8fb19SBen Gras void
svc_getreq_poll(struct pollfd * pfdp,int pollretval)717f14fb602SLionel Sambuc svc_getreq_poll(struct pollfd *pfdp, int pollretval)
7182fe8fb19SBen Gras {
7192fe8fb19SBen Gras 	int i;
7202fe8fb19SBen Gras 	int fds_found;
7212fe8fb19SBen Gras 
7222fe8fb19SBen Gras 	_DIAGASSERT(pfdp != NULL);
7232fe8fb19SBen Gras 
7242fe8fb19SBen Gras 	for (i = fds_found = 0; fds_found < pollretval; i++) {
7252fe8fb19SBen Gras 		struct pollfd *p = &pfdp[i];
7262fe8fb19SBen Gras 
7272fe8fb19SBen Gras 		if (p->revents) {
7282fe8fb19SBen Gras 			/* fd has input waiting */
7292fe8fb19SBen Gras 			fds_found++;
7302fe8fb19SBen Gras 			/*
7312fe8fb19SBen Gras 			 *	We assume that this function is only called
7322fe8fb19SBen Gras 			 *	via someone select()ing from svc_fdset or
7332fe8fb19SBen Gras 			 *	pollts()ing from svc_pollset[].  Thus it's safe
7342fe8fb19SBen Gras 			 *	to handle the POLLNVAL event by simply turning
7352fe8fb19SBen Gras 			 *	the corresponding bit off in svc_fdset.  The
7362fe8fb19SBen Gras 			 *	svc_pollset[] array is derived from svc_fdset
7372fe8fb19SBen Gras 			 *	and so will also be updated eventually.
7382fe8fb19SBen Gras 			 *
7392fe8fb19SBen Gras 			 *	XXX Should we do an xprt_unregister() instead?
7402fe8fb19SBen Gras 			 */
7412fe8fb19SBen Gras 			if (p->revents & POLLNVAL) {
7422fe8fb19SBen Gras 				rwlock_wrlock(&svc_fd_lock);
743*84d9c625SLionel Sambuc 				FD_CLR(p->fd, get_fdset());
7442fe8fb19SBen Gras 				rwlock_unlock(&svc_fd_lock);
7452fe8fb19SBen Gras 			} else
7462fe8fb19SBen Gras 				svc_getreq_common(p->fd);
7472fe8fb19SBen Gras 		}
7482fe8fb19SBen Gras 	}
7492fe8fb19SBen Gras }
7502fe8fb19SBen Gras 
7512fe8fb19SBen Gras bool_t
rpc_control(int what,void * arg)7522fe8fb19SBen Gras rpc_control(int what, void *arg)
7532fe8fb19SBen Gras {
7542fe8fb19SBen Gras 	int val;
7552fe8fb19SBen Gras 
7562fe8fb19SBen Gras 	switch (what) {
7572fe8fb19SBen Gras 	case RPC_SVC_CONNMAXREC_SET:
7582fe8fb19SBen Gras 		val = *(int *)arg;
7592fe8fb19SBen Gras 		if (val <= 0)
7602fe8fb19SBen Gras 			return FALSE;
7612fe8fb19SBen Gras 		__svc_maxrec = val;
7622fe8fb19SBen Gras 		return TRUE;
7632fe8fb19SBen Gras 	case RPC_SVC_CONNMAXREC_GET:
7642fe8fb19SBen Gras 		*(int *)arg = __svc_maxrec;
7652fe8fb19SBen Gras 		return TRUE;
7662fe8fb19SBen Gras 	default:
7672fe8fb19SBen Gras 		break;
7682fe8fb19SBen Gras 	}
7692fe8fb19SBen Gras 	return FALSE;
7702fe8fb19SBen Gras }
771