svc.c revision 92990
174462Salfred/*	$NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $	*/
274462Salfred
31901Swollman/*
41901Swollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
51901Swollman * unrestricted use provided that this legend is included on all tape
61901Swollman * media and as a part of the software program in whole or part.  Users
71901Swollman * may copy or modify Sun RPC without charge, but are not authorized
81901Swollman * to license or distribute it to anyone else except as part of a product or
91901Swollman * program developed by the user.
108870Srgrimes *
111901Swollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
121901Swollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
131901Swollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
148870Srgrimes *
151901Swollman * Sun RPC is provided with no support and without any obligation on the
161901Swollman * part of Sun Microsystems, Inc. to assist in its use, correction,
171901Swollman * modification or enhancement.
188870Srgrimes *
191901Swollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
201901Swollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
211901Swollman * OR ANY PART THEREOF.
228870Srgrimes *
231901Swollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue
241901Swollman * or profits or other special, indirect and consequential damages, even if
251901Swollman * Sun has been advised of the possibility of such damages.
268870Srgrimes *
271901Swollman * Sun Microsystems, Inc.
281901Swollman * 2550 Garcia Avenue
291901Swollman * Mountain View, California  94043
301901Swollman */
311901Swollman
328870Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3392990Sobrienstatic char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
3492990Sobrienstatic char *sccsid = "@(#)svc.c	2.4 88/08/11 4.0 RPCSRC";
351901Swollman#endif
3692990Sobrien#include <sys/cdefs.h>
3792990Sobrien__FBSDID("$FreeBSD: head/lib/libc/rpc/svc.c 92990 2002-03-22 23:18:37Z obrien $");
381901Swollman
391901Swollman/*
401901Swollman * svc.c, Server-side remote procedure call interface.
411901Swollman *
421901Swollman * There are two sets of procedures here.  The xprt routines are
431901Swollman * for handling transport handles.  The svc routines handle the
441901Swollman * list of service routines.
451901Swollman *
461901Swollman * Copyright (C) 1984, Sun Microsystems, Inc.
471901Swollman */
481901Swollman
4975094Siedowse#include "namespace.h"
5074462Salfred#include "reentrant.h"
5174462Salfred#include <sys/types.h>
5274462Salfred#include <sys/poll.h>
5374462Salfred#include <assert.h>
5474462Salfred#include <errno.h>
5574462Salfred#include <stdlib.h>
5611666Sphk#include <string.h>
5774462Salfred
581901Swollman#include <rpc/rpc.h>
5974462Salfred#ifdef PORTMAP
601901Swollman#include <rpc/pmap_clnt.h>
6174462Salfred#endif				/* PORTMAP */
6274462Salfred#include "un-namespace.h"
631901Swollman
6474462Salfred#include "rpc_com.h"
6574462Salfred
661901Swollmanstatic SVCXPRT **xports;
671901Swollman
681901Swollman#define	RQCRED_SIZE	400		/* this size is excessive */
691901Swollman
7074462Salfred#define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
7174462Salfred#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
7274462Salfred
7321087Speter#define max(a, b) (a > b ? a : b)
7416270Sjraynard
751901Swollman/*
761901Swollman * The services list
771901Swollman * Each entry represents a set of procedures (an rpc program).
781901Swollman * The dispatch routine takes request structs and runs the
791901Swollman * apropriate procedure.
801901Swollman */
811901Swollmanstatic struct svc_callout {
821901Swollman	struct svc_callout *sc_next;
8374462Salfred	rpcprog_t	    sc_prog;
8474462Salfred	rpcvers_t	    sc_vers;
8574462Salfred	char		   *sc_netid;
8692905Sobrien	void		    (*sc_dispatch)(struct svc_req *, SVCXPRT *);
871901Swollman} *svc_head;
881901Swollman
8974462Salfredextern rwlock_t svc_lock;
9074462Salfredextern rwlock_t svc_fd_lock;
911901Swollman
9292941Sobrienstatic struct svc_callout *svc_find(rpcprog_t, rpcvers_t,
9392941Sobrien    struct svc_callout **, char *);
9421087Speter
951901Swollman/* ***************  SVCXPRT related stuff **************** */
961901Swollman
971901Swollman/*
981901Swollman * Activate a transport handle.
991901Swollman */
1001901Swollmanvoid
1011901Swollmanxprt_register(xprt)
1021901Swollman	SVCXPRT *xprt;
1031901Swollman{
10474462Salfred	int sock;
1051901Swollman
10674462Salfred	assert(xprt != NULL);
10721087Speter
10874462Salfred	sock = xprt->xp_fd;
10974462Salfred
11074462Salfred	rwlock_wrlock(&svc_fd_lock);
11174462Salfred	if (xports == NULL) {
11274462Salfred		xports = (SVCXPRT **)
11374462Salfred			mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
11474462Salfred		if (xports == NULL)
11574462Salfred			return;
11674462Salfred		memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
1171901Swollman	}
11874462Salfred	if (sock < FD_SETSIZE) {
11974462Salfred		xports[sock] = xprt;
1201901Swollman		FD_SET(sock, &svc_fdset);
12174462Salfred		svc_maxfd = max(svc_maxfd, sock);
1221901Swollman	}
12374462Salfred	rwlock_unlock(&svc_fd_lock);
1241901Swollman}
1251901Swollman
1261901Swollman/*
1278870Srgrimes * De-activate a transport handle.
1281901Swollman */
1291901Swollmanvoid
13074462Salfredxprt_unregister(xprt)
1311901Swollman	SVCXPRT *xprt;
1328870Srgrimes{
13374462Salfred	int sock;
1341901Swollman
13574462Salfred	assert(xprt != NULL);
13674462Salfred
13774462Salfred	sock = xprt->xp_fd;
13874462Salfred
13974462Salfred	rwlock_wrlock(&svc_fd_lock);
14074462Salfred	if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) {
14174462Salfred		xports[sock] = NULL;
14274462Salfred		FD_CLR(sock, &svc_fdset);
14374462Salfred		if (sock >= svc_maxfd) {
14474462Salfred			for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
14521087Speter				if (xports[svc_maxfd])
14621087Speter					break;
14721087Speter		}
1481901Swollman	}
14974462Salfred	rwlock_unlock(&svc_fd_lock);
1501901Swollman}
1511901Swollman
15274462Salfred/*
15374462Salfred * Add a service program to the callout list.
15474462Salfred * The dispatch routine will be called when a rpc request for this
15574462Salfred * program number comes in.
15674462Salfred */
15774462Salfredbool_t
15874462Salfredsvc_reg(xprt, prog, vers, dispatch, nconf)
15974462Salfred	SVCXPRT *xprt;
16074462Salfred	const rpcprog_t prog;
16174462Salfred	const rpcvers_t vers;
16292905Sobrien	void (*dispatch)(struct svc_req *, SVCXPRT *);
16374462Salfred	const struct netconfig *nconf;
16474462Salfred{
16574462Salfred	bool_t dummy;
16674462Salfred	struct svc_callout *prev;
16774462Salfred	struct svc_callout *s;
16874462Salfred	struct netconfig *tnconf;
16974462Salfred	char *netid = NULL;
17074462Salfred	int flag = 0;
1711901Swollman
17274462Salfred/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
17374462Salfred
17474462Salfred	if (xprt->xp_netid) {
17574462Salfred		netid = strdup(xprt->xp_netid);
17674462Salfred		flag = 1;
17774462Salfred	} else if (nconf && nconf->nc_netid) {
17874462Salfred		netid = strdup(nconf->nc_netid);
17974462Salfred		flag = 1;
18074462Salfred	} else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
18174462Salfred		netid = strdup(tnconf->nc_netid);
18274462Salfred		flag = 1;
18374462Salfred		freenetconfigent(tnconf);
18474462Salfred	} /* must have been created with svc_raw_create */
18574462Salfred	if ((netid == NULL) && (flag == 1)) {
18674462Salfred		return (FALSE);
18774462Salfred	}
18874462Salfred
18974462Salfred	rwlock_wrlock(&svc_lock);
19074462Salfred	if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
19174462Salfred		if (netid)
19274462Salfred			free(netid);
19374462Salfred		if (s->sc_dispatch == dispatch)
19474462Salfred			goto rpcb_it; /* he is registering another xptr */
19574462Salfred		rwlock_unlock(&svc_lock);
19674462Salfred		return (FALSE);
19774462Salfred	}
19874462Salfred	s = mem_alloc(sizeof (struct svc_callout));
19974462Salfred	if (s == NULL) {
20074462Salfred		if (netid)
20174462Salfred			free(netid);
20274462Salfred		rwlock_unlock(&svc_lock);
20374462Salfred		return (FALSE);
20474462Salfred	}
20574462Salfred
20674462Salfred	s->sc_prog = prog;
20774462Salfred	s->sc_vers = vers;
20874462Salfred	s->sc_dispatch = dispatch;
20974462Salfred	s->sc_netid = netid;
21074462Salfred	s->sc_next = svc_head;
21174462Salfred	svc_head = s;
21274462Salfred
21374462Salfred	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
21474462Salfred		((SVCXPRT *) xprt)->xp_netid = strdup(netid);
21574462Salfred
21674462Salfredrpcb_it:
21774462Salfred	rwlock_unlock(&svc_lock);
21874462Salfred	/* now register the information with the local binder service */
21974462Salfred	if (nconf) {
22074462Salfred		/*LINTED const castaway*/
22174462Salfred		dummy = rpcb_set(prog, vers, (struct netconfig *) nconf,
22274462Salfred		&((SVCXPRT *) xprt)->xp_ltaddr);
22374462Salfred		return (dummy);
22474462Salfred	}
22574462Salfred	return (TRUE);
22674462Salfred}
22774462Salfred
22874462Salfred/*
22974462Salfred * Remove a service program from the callout list.
23074462Salfred */
23174462Salfredvoid
23274462Salfredsvc_unreg(prog, vers)
23374462Salfred	const rpcprog_t prog;
23474462Salfred	const rpcvers_t vers;
23574462Salfred{
23674462Salfred	struct svc_callout *prev;
23774462Salfred	struct svc_callout *s;
23874462Salfred
23974462Salfred	/* unregister the information anyway */
24074462Salfred	(void) rpcb_unset(prog, vers, NULL);
24174462Salfred	rwlock_wrlock(&svc_lock);
24274462Salfred	while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
24374462Salfred		if (prev == NULL) {
24474462Salfred			svc_head = s->sc_next;
24574462Salfred		} else {
24674462Salfred			prev->sc_next = s->sc_next;
24774462Salfred		}
24874462Salfred		s->sc_next = NULL;
24974462Salfred		if (s->sc_netid)
25074462Salfred			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
25174462Salfred		mem_free(s, sizeof (struct svc_callout));
25274462Salfred	}
25374462Salfred	rwlock_unlock(&svc_lock);
25474462Salfred}
25574462Salfred
2561901Swollman/* ********************** CALLOUT list related stuff ************* */
2571901Swollman
25874462Salfred#ifdef PORTMAP
2591901Swollman/*
2601901Swollman * Add a service program to the callout list.
2611901Swollman * The dispatch routine will be called when a rpc request for this
2621901Swollman * program number comes in.
2631901Swollman */
2641901Swollmanbool_t
2651901Swollmansvc_register(xprt, prog, vers, dispatch, protocol)
2661901Swollman	SVCXPRT *xprt;
2671901Swollman	u_long prog;
2681901Swollman	u_long vers;
26992905Sobrien	void (*dispatch)(struct svc_req *, SVCXPRT *);
2701901Swollman	int protocol;
2711901Swollman{
2721901Swollman	struct svc_callout *prev;
27374462Salfred	struct svc_callout *s;
2741901Swollman
27574462Salfred	assert(xprt != NULL);
27674462Salfred	assert(dispatch != NULL);
27774462Salfred
27874462Salfred	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
27974462Salfred	    NULL) {
2801901Swollman		if (s->sc_dispatch == dispatch)
2811901Swollman			goto pmap_it;  /* he is registering another xptr */
2821901Swollman		return (FALSE);
2831901Swollman	}
28474462Salfred	s = mem_alloc(sizeof(struct svc_callout));
28574462Salfred	if (s == NULL) {
2861901Swollman		return (FALSE);
2871901Swollman	}
28874462Salfred	s->sc_prog = (rpcprog_t)prog;
28974462Salfred	s->sc_vers = (rpcvers_t)vers;
2901901Swollman	s->sc_dispatch = dispatch;
2911901Swollman	s->sc_next = svc_head;
2921901Swollman	svc_head = s;
2931901Swollmanpmap_it:
2941901Swollman	/* now register the information with the local binder service */
2951901Swollman	if (protocol) {
2961901Swollman		return (pmap_set(prog, vers, protocol, xprt->xp_port));
2971901Swollman	}
2981901Swollman	return (TRUE);
2991901Swollman}
3001901Swollman
3011901Swollman/*
3021901Swollman * Remove a service program from the callout list.
3031901Swollman */
3041901Swollmanvoid
3051901Swollmansvc_unregister(prog, vers)
3061901Swollman	u_long prog;
3071901Swollman	u_long vers;
3081901Swollman{
3091901Swollman	struct svc_callout *prev;
31074462Salfred	struct svc_callout *s;
3111901Swollman
31274462Salfred	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
31374462Salfred	    NULL)
3141901Swollman		return;
31574462Salfred	if (prev == NULL) {
3161901Swollman		svc_head = s->sc_next;
3171901Swollman	} else {
3181901Swollman		prev->sc_next = s->sc_next;
3191901Swollman	}
32074462Salfred	s->sc_next = NULL;
32174462Salfred	mem_free(s, sizeof(struct svc_callout));
3221901Swollman	/* now unregister the information with the local binder service */
3231901Swollman	(void)pmap_unset(prog, vers);
3241901Swollman}
32574462Salfred#endif				/* PORTMAP */
3261901Swollman
3271901Swollman/*
3281901Swollman * Search the callout list for a program number, return the callout
3291901Swollman * struct.
3301901Swollman */
3311901Swollmanstatic struct svc_callout *
33274462Salfredsvc_find(prog, vers, prev, netid)
33374462Salfred	rpcprog_t prog;
33474462Salfred	rpcvers_t vers;
3351901Swollman	struct svc_callout **prev;
33674462Salfred	char *netid;
3371901Swollman{
33874462Salfred	struct svc_callout *s, *p;
3391901Swollman
34074462Salfred	assert(prev != NULL);
34174462Salfred
34274462Salfred	p = NULL;
34374462Salfred	for (s = svc_head; s != NULL; s = s->sc_next) {
34474462Salfred		if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
34574462Salfred		    ((netid == NULL) || (s->sc_netid == NULL) ||
34674462Salfred		    (strcmp(netid, s->sc_netid) == 0)))
34774462Salfred			break;
3481901Swollman		p = s;
3491901Swollman	}
3501901Swollman	*prev = p;
3511901Swollman	return (s);
3521901Swollman}
3531901Swollman
3541901Swollman/* ******************* REPLY GENERATION ROUTINES  ************ */
3551901Swollman
3561901Swollman/*
3571901Swollman * Send a reply to an rpc request
3581901Swollman */
3591901Swollmanbool_t
3601901Swollmansvc_sendreply(xprt, xdr_results, xdr_location)
36174462Salfred	SVCXPRT *xprt;
3621901Swollman	xdrproc_t xdr_results;
3631901Swollman	caddr_t xdr_location;
3641901Swollman{
36574462Salfred	struct rpc_msg rply;
3661901Swollman
36774462Salfred	assert(xprt != NULL);
36874462Salfred
36974462Salfred	rply.rm_direction = REPLY;
37074462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
37174462Salfred	rply.acpted_rply.ar_verf = xprt->xp_verf;
3721901Swollman	rply.acpted_rply.ar_stat = SUCCESS;
3731901Swollman	rply.acpted_rply.ar_results.where = xdr_location;
3741901Swollman	rply.acpted_rply.ar_results.proc = xdr_results;
37574462Salfred	return (SVC_REPLY(xprt, &rply));
3761901Swollman}
3771901Swollman
3781901Swollman/*
3791901Swollman * No procedure error reply
3801901Swollman */
3811901Swollmanvoid
3821901Swollmansvcerr_noproc(xprt)
38374462Salfred	SVCXPRT *xprt;
3841901Swollman{
3851901Swollman	struct rpc_msg rply;
3861901Swollman
38774462Salfred	assert(xprt != NULL);
38874462Salfred
3891901Swollman	rply.rm_direction = REPLY;
3901901Swollman	rply.rm_reply.rp_stat = MSG_ACCEPTED;
3911901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
3921901Swollman	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
3931901Swollman	SVC_REPLY(xprt, &rply);
3941901Swollman}
3951901Swollman
3961901Swollman/*
3971901Swollman * Can't decode args error reply
3981901Swollman */
3991901Swollmanvoid
4001901Swollmansvcerr_decode(xprt)
40174462Salfred	SVCXPRT *xprt;
4021901Swollman{
40374462Salfred	struct rpc_msg rply;
4041901Swollman
40574462Salfred	assert(xprt != NULL);
40674462Salfred
40774462Salfred	rply.rm_direction = REPLY;
40874462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4091901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
4101901Swollman	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
41174462Salfred	SVC_REPLY(xprt, &rply);
4121901Swollman}
4131901Swollman
4141901Swollman/*
4151901Swollman * Some system error
4161901Swollman */
4171901Swollmanvoid
4181901Swollmansvcerr_systemerr(xprt)
41974462Salfred	SVCXPRT *xprt;
4201901Swollman{
42174462Salfred	struct rpc_msg rply;
4221901Swollman
42374462Salfred	assert(xprt != NULL);
42474462Salfred
42574462Salfred	rply.rm_direction = REPLY;
42674462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4271901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
4281901Swollman	rply.acpted_rply.ar_stat = SYSTEM_ERR;
42974462Salfred	SVC_REPLY(xprt, &rply);
4301901Swollman}
4311901Swollman
43274462Salfred#if 0
4331901Swollman/*
43474462Salfred * Tell RPC package to not complain about version errors to the client.	 This
43574462Salfred * is useful when revving broadcast protocols that sit on a fixed address.
43674462Salfred * There is really one (or should be only one) example of this kind of
43774462Salfred * protocol: the portmapper (or rpc binder).
43874462Salfred */
43974462Salfredvoid
44074462Salfred__svc_versquiet_on(xprt)
44174462Salfred	SVCXPRT *xprt;
44274462Salfred{
44374462Salfred	u_long	tmp;
44474462Salfred
44574462Salfred	tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
44674462Salfred	xprt->xp_p3 = (caddr_t) tmp;
44774462Salfred}
44874462Salfred
44974462Salfredvoid
45074462Salfred__svc_versquiet_off(xprt)
45174462Salfred	SVCXPRT *xprt;
45274462Salfred{
45374462Salfred	u_long	tmp;
45474462Salfred
45574462Salfred	tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
45674462Salfred	xprt->xp_p3 = (caddr_t) tmp;
45774462Salfred}
45874462Salfred
45974462Salfredvoid
46074462Salfredsvc_versquiet(xprt)
46174462Salfred	SVCXPRT *xprt;
46274462Salfred{
46374462Salfred	__svc_versquiet_on(xprt);
46474462Salfred}
46574462Salfred
46674462Salfredint
46774462Salfred__svc_versquiet_get(xprt)
46874462Salfred	SVCXPRT *xprt;
46974462Salfred{
47074462Salfred	return ((int) xprt->xp_p3) & SVC_VERSQUIET;
47174462Salfred}
47274462Salfred#endif
47374462Salfred
47474462Salfred/*
4751901Swollman * Authentication error reply
4761901Swollman */
4771901Swollmanvoid
4781901Swollmansvcerr_auth(xprt, why)
4791901Swollman	SVCXPRT *xprt;
4801901Swollman	enum auth_stat why;
4811901Swollman{
4821901Swollman	struct rpc_msg rply;
4831901Swollman
48474462Salfred	assert(xprt != NULL);
48574462Salfred
4861901Swollman	rply.rm_direction = REPLY;
4871901Swollman	rply.rm_reply.rp_stat = MSG_DENIED;
4881901Swollman	rply.rjcted_rply.rj_stat = AUTH_ERROR;
4891901Swollman	rply.rjcted_rply.rj_why = why;
4901901Swollman	SVC_REPLY(xprt, &rply);
4911901Swollman}
4921901Swollman
4931901Swollman/*
4941901Swollman * Auth too weak error reply
4951901Swollman */
4961901Swollmanvoid
4971901Swollmansvcerr_weakauth(xprt)
4981901Swollman	SVCXPRT *xprt;
4991901Swollman{
5001901Swollman
50174462Salfred	assert(xprt != NULL);
50274462Salfred
5031901Swollman	svcerr_auth(xprt, AUTH_TOOWEAK);
5041901Swollman}
5051901Swollman
5061901Swollman/*
5071901Swollman * Program unavailable error reply
5081901Swollman */
50974462Salfredvoid
5101901Swollmansvcerr_noprog(xprt)
51174462Salfred	SVCXPRT *xprt;
5121901Swollman{
51374462Salfred	struct rpc_msg rply;
5141901Swollman
51574462Salfred	assert(xprt != NULL);
51674462Salfred
51774462Salfred	rply.rm_direction = REPLY;
51874462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
51974462Salfred	rply.acpted_rply.ar_verf = xprt->xp_verf;
5201901Swollman	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
5211901Swollman	SVC_REPLY(xprt, &rply);
5221901Swollman}
5231901Swollman
5241901Swollman/*
5251901Swollman * Program version mismatch error reply
5261901Swollman */
52774462Salfredvoid
5281901Swollmansvcerr_progvers(xprt, low_vers, high_vers)
52974462Salfred	SVCXPRT *xprt;
53074462Salfred	rpcvers_t low_vers;
53174462Salfred	rpcvers_t high_vers;
5321901Swollman{
5331901Swollman	struct rpc_msg rply;
5341901Swollman
53574462Salfred	assert(xprt != NULL);
53674462Salfred
5371901Swollman	rply.rm_direction = REPLY;
5381901Swollman	rply.rm_reply.rp_stat = MSG_ACCEPTED;
5391901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
5401901Swollman	rply.acpted_rply.ar_stat = PROG_MISMATCH;
54174462Salfred	rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
54274462Salfred	rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
5431901Swollman	SVC_REPLY(xprt, &rply);
5441901Swollman}
5451901Swollman
5461901Swollman/* ******************* SERVER INPUT STUFF ******************* */
5471901Swollman
5481901Swollman/*
5491901Swollman * Get server side input from some transport.
5501901Swollman *
5511901Swollman * Statement of authentication parameters management:
5521901Swollman * This function owns and manages all authentication parameters, specifically
5531901Swollman * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
5541901Swollman * the "cooked" credentials (rqst->rq_clntcred).
5551901Swollman * However, this function does not know the structure of the cooked
5568870Srgrimes * credentials, so it make the following assumptions:
5571901Swollman *   a) the structure is contiguous (no pointers), and
5588870Srgrimes *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
5591901Swollman * In all events, all three parameters are freed upon exit from this routine.
5601901Swollman * The storage is trivially management on the call stack in user land, but
5611901Swollman * is mallocated in kernel land.
5621901Swollman */
5631901Swollman
5641901Swollmanvoid
5651901Swollmansvc_getreq(rdfds)
5661901Swollman	int rdfds;
5671901Swollman{
5681901Swollman	fd_set readfds;
5691901Swollman
5701901Swollman	FD_ZERO(&readfds);
5711901Swollman	readfds.fds_bits[0] = rdfds;
5721901Swollman	svc_getreqset(&readfds);
5731901Swollman}
5741901Swollman
5751901Swollmanvoid
5761901Swollmansvc_getreqset(readfds)
5771901Swollman	fd_set *readfds;
5781901Swollman{
57974462Salfred	int bit, fd;
58074462Salfred	fd_mask mask, *maskp;
58174462Salfred	int sock;
58274462Salfred
58374462Salfred	assert(readfds != NULL);
58474462Salfred
58574462Salfred	maskp = readfds->fds_bits;
58674462Salfred	for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
58774462Salfred	    for (mask = *maskp++; (bit = ffs(mask)) != 0;
58874462Salfred		mask ^= (1 << (bit - 1))) {
58974462Salfred		/* sock has input waiting */
59074462Salfred		fd = sock + bit - 1;
59174462Salfred		svc_getreq_common(fd);
59274462Salfred	    }
59374462Salfred	}
59421087Speter}
59521087Speter
59621087Spetervoid
59774462Salfredsvc_getreq_common(fd)
59874462Salfred	int fd;
5991901Swollman{
60074462Salfred	SVCXPRT *xprt;
60174462Salfred	struct svc_req r;
6021901Swollman	struct rpc_msg msg;
6031901Swollman	int prog_found;
60474462Salfred	rpcvers_t low_vers;
60574462Salfred	rpcvers_t high_vers;
60674462Salfred	enum xprt_stat stat;
6071901Swollman	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
60874462Salfred
6091901Swollman	msg.rm_call.cb_cred.oa_base = cred_area;
6101901Swollman	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
6111901Swollman	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
6121901Swollman
61374462Salfred	rwlock_rdlock(&svc_fd_lock);
61474462Salfred	xprt = xports[fd];
61574462Salfred	rwlock_unlock(&svc_fd_lock);
61674462Salfred	if (xprt == NULL)
61774462Salfred		/* But do we control sock? */
61874462Salfred		return;
61974462Salfred	/* now receive msgs from xprtprt (support batch calls) */
62074462Salfred	do {
62174462Salfred		if (SVC_RECV(xprt, &msg)) {
6221901Swollman
62374462Salfred			/* now find the exported program and call it */
62474462Salfred			struct svc_callout *s;
62574462Salfred			enum auth_stat why;
6261901Swollman
62774462Salfred			r.rq_xprt = xprt;
62874462Salfred			r.rq_prog = msg.rm_call.cb_prog;
62974462Salfred			r.rq_vers = msg.rm_call.cb_vers;
63074462Salfred			r.rq_proc = msg.rm_call.cb_proc;
63174462Salfred			r.rq_cred = msg.rm_call.cb_cred;
63274462Salfred			/* first authenticate the message */
63374462Salfred			if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
63474462Salfred				svcerr_auth(xprt, why);
63574462Salfred				goto call_done;
6361901Swollman			}
63774462Salfred			/* now match message with a registered service*/
63874462Salfred			prog_found = FALSE;
63974462Salfred			low_vers = (rpcvers_t) -1L;
64074462Salfred			high_vers = (rpcvers_t) 0L;
64174462Salfred			for (s = svc_head; s != NULL; s = s->sc_next) {
64274462Salfred				if (s->sc_prog == r.rq_prog) {
64374462Salfred					if (s->sc_vers == r.rq_vers) {
64474462Salfred						(*s->sc_dispatch)(&r, xprt);
64574462Salfred						goto call_done;
64674462Salfred					}  /* found correct version */
64774462Salfred					prog_found = TRUE;
64874462Salfred					if (s->sc_vers < low_vers)
64974462Salfred						low_vers = s->sc_vers;
65074462Salfred					if (s->sc_vers > high_vers)
65174462Salfred						high_vers = s->sc_vers;
65274462Salfred				}   /* found correct program */
6531901Swollman			}
65474462Salfred			/*
65574462Salfred			 * if we got here, the program or version
65674462Salfred			 * is not served ...
65774462Salfred			 */
65874462Salfred			if (prog_found)
65974462Salfred				svcerr_progvers(xprt, low_vers, high_vers);
66074462Salfred			else
66174462Salfred				 svcerr_noprog(xprt);
66274462Salfred			/* Fall through to ... */
66374462Salfred		}
66474462Salfred		/*
66574462Salfred		 * Check if the xprt has been disconnected in a
66674462Salfred		 * recursive call in the service dispatch routine.
66774462Salfred		 * If so, then break.
66874462Salfred		 */
66974462Salfred		rwlock_rdlock(&svc_fd_lock);
67074462Salfred		if (xprt != xports[fd]) {
67174462Salfred			rwlock_unlock(&svc_fd_lock);
67274462Salfred			break;
67374462Salfred		}
67474462Salfred		rwlock_unlock(&svc_fd_lock);
67574462Salfredcall_done:
67674462Salfred		if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
67774462Salfred			SVC_DESTROY(xprt);
67874462Salfred			break;
67974462Salfred		}
68074462Salfred	} while (stat == XPRT_MOREREQS);
68174462Salfred}
68274462Salfred
68374462Salfred
68474462Salfredvoid
68574462Salfredsvc_getreq_poll(pfdp, pollretval)
68674462Salfred	struct pollfd	*pfdp;
68774462Salfred	int	pollretval;
68874462Salfred{
68974462Salfred	int i;
69074462Salfred	int fds_found;
69174462Salfred
69274462Salfred	for (i = fds_found = 0; fds_found < pollretval; i++) {
69374462Salfred		struct pollfd *p = &pfdp[i];
69474462Salfred
69574462Salfred		if (p->revents) {
69674462Salfred			/* fd has input waiting */
69774462Salfred			fds_found++;
69874462Salfred			/*
69974462Salfred			 *	We assume that this function is only called
70074462Salfred			 *	via someone _select()ing from svc_fdset or
70174462Salfred			 *	_poll()ing from svc_pollset[].  Thus it's safe
70274462Salfred			 *	to handle the POLLNVAL event by simply turning
70374462Salfred			 *	the corresponding bit off in svc_fdset.  The
70474462Salfred			 *	svc_pollset[] array is derived from svc_fdset
70574462Salfred			 *	and so will also be updated eventually.
70674462Salfred			 *
70774462Salfred			 *	XXX Should we do an xprt_unregister() instead?
70874462Salfred			 */
70974462Salfred			if (p->revents & POLLNVAL) {
71074462Salfred				rwlock_wrlock(&svc_fd_lock);
71174462Salfred				FD_CLR(p->fd, &svc_fdset);
71274462Salfred				rwlock_unlock(&svc_fd_lock);
71374462Salfred			} else
71474462Salfred				svc_getreq_common(p->fd);
71574462Salfred		}
7161901Swollman	}
7171901Swollman}
718