svc.c revision 177633
1177633Sdfr/*	$NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $	*/
2177633Sdfr
3177633Sdfr/*
4177633Sdfr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5177633Sdfr * unrestricted use provided that this legend is included on all tape
6177633Sdfr * media and as a part of the software program in whole or part.  Users
7177633Sdfr * may copy or modify Sun RPC without charge, but are not authorized
8177633Sdfr * to license or distribute it to anyone else except as part of a product or
9177633Sdfr * program developed by the user.
10177633Sdfr *
11177633Sdfr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12177633Sdfr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13177633Sdfr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14177633Sdfr *
15177633Sdfr * Sun RPC is provided with no support and without any obligation on the
16177633Sdfr * part of Sun Microsystems, Inc. to assist in its use, correction,
17177633Sdfr * modification or enhancement.
18177633Sdfr *
19177633Sdfr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20177633Sdfr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21177633Sdfr * OR ANY PART THEREOF.
22177633Sdfr *
23177633Sdfr * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24177633Sdfr * or profits or other special, indirect and consequential damages, even if
25177633Sdfr * Sun has been advised of the possibility of such damages.
26177633Sdfr *
27177633Sdfr * Sun Microsystems, Inc.
28177633Sdfr * 2550 Garcia Avenue
29177633Sdfr * Mountain View, California  94043
30177633Sdfr */
31177633Sdfr
32177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
33177633Sdfrstatic char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
34177633Sdfrstatic char *sccsid = "@(#)svc.c	2.4 88/08/11 4.0 RPCSRC";
35177633Sdfr#endif
36177633Sdfr#include <sys/cdefs.h>
37177633Sdfr__FBSDID("$FreeBSD: head/sys/rpc/svc.c 177633 2008-03-26 15:23:12Z dfr $");
38177633Sdfr
39177633Sdfr/*
40177633Sdfr * svc.c, Server-side remote procedure call interface.
41177633Sdfr *
42177633Sdfr * There are two sets of procedures here.  The xprt routines are
43177633Sdfr * for handling transport handles.  The svc routines handle the
44177633Sdfr * list of service routines.
45177633Sdfr *
46177633Sdfr * Copyright (C) 1984, Sun Microsystems, Inc.
47177633Sdfr */
48177633Sdfr
49177633Sdfr#include <sys/param.h>
50177633Sdfr#include <sys/lock.h>
51177633Sdfr#include <sys/kernel.h>
52177633Sdfr#include <sys/malloc.h>
53177633Sdfr#include <sys/mutex.h>
54177633Sdfr#include <sys/queue.h>
55177633Sdfr#include <sys/systm.h>
56177633Sdfr#include <sys/ucred.h>
57177633Sdfr
58177633Sdfr#include <rpc/rpc.h>
59177633Sdfr#include <rpc/rpcb_clnt.h>
60177633Sdfr
61177633Sdfr#include "rpc_com.h"
62177633Sdfr
63177633Sdfr#define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
64177633Sdfr#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
65177633Sdfr
66177633Sdfrstatic struct svc_callout *svc_find(SVCPOOL *pool, rpcprog_t, rpcvers_t,
67177633Sdfr    char *);
68177633Sdfrstatic void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock);
69177633Sdfr
70177633Sdfr/* ***************  SVCXPRT related stuff **************** */
71177633Sdfr
72177633SdfrSVCPOOL*
73177633Sdfrsvcpool_create(void)
74177633Sdfr{
75177633Sdfr	SVCPOOL *pool;
76177633Sdfr
77177633Sdfr	pool = malloc(sizeof(SVCPOOL), M_RPC, M_WAITOK|M_ZERO);
78177633Sdfr
79177633Sdfr	mtx_init(&pool->sp_lock, "sp_lock", NULL, MTX_DEF);
80177633Sdfr	TAILQ_INIT(&pool->sp_xlist);
81177633Sdfr	TAILQ_INIT(&pool->sp_active);
82177633Sdfr	TAILQ_INIT(&pool->sp_callouts);
83177633Sdfr
84177633Sdfr	return pool;
85177633Sdfr}
86177633Sdfr
87177633Sdfrvoid
88177633Sdfrsvcpool_destroy(SVCPOOL *pool)
89177633Sdfr{
90177633Sdfr	SVCXPRT *xprt;
91177633Sdfr	struct svc_callout *s;
92177633Sdfr
93177633Sdfr	mtx_lock(&pool->sp_lock);
94177633Sdfr
95177633Sdfr	while (TAILQ_FIRST(&pool->sp_xlist)) {
96177633Sdfr		xprt = TAILQ_FIRST(&pool->sp_xlist);
97177633Sdfr		mtx_unlock(&pool->sp_lock);
98177633Sdfr		SVC_DESTROY(xprt);
99177633Sdfr		mtx_lock(&pool->sp_lock);
100177633Sdfr	}
101177633Sdfr
102177633Sdfr	while (TAILQ_FIRST(&pool->sp_callouts)) {
103177633Sdfr		s = TAILQ_FIRST(&pool->sp_callouts);
104177633Sdfr		mtx_unlock(&pool->sp_lock);
105177633Sdfr		svc_unreg(pool, s->sc_prog, s->sc_vers);
106177633Sdfr		mtx_lock(&pool->sp_lock);
107177633Sdfr	}
108177633Sdfr
109177633Sdfr	mtx_destroy(&pool->sp_lock);
110177633Sdfr	free(pool, M_RPC);
111177633Sdfr}
112177633Sdfr
113177633Sdfr/*
114177633Sdfr * Activate a transport handle.
115177633Sdfr */
116177633Sdfrvoid
117177633Sdfrxprt_register(SVCXPRT *xprt)
118177633Sdfr{
119177633Sdfr	SVCPOOL *pool = xprt->xp_pool;
120177633Sdfr
121177633Sdfr	mtx_lock(&pool->sp_lock);
122177633Sdfr	xprt->xp_registered = TRUE;
123177633Sdfr	xprt->xp_active = FALSE;
124177633Sdfr	TAILQ_INSERT_TAIL(&pool->sp_xlist, xprt, xp_link);
125177633Sdfr	mtx_unlock(&pool->sp_lock);
126177633Sdfr}
127177633Sdfr
128177633Sdfrvoid
129177633Sdfrxprt_unregister(SVCXPRT *xprt)
130177633Sdfr{
131177633Sdfr	__xprt_do_unregister(xprt, TRUE);
132177633Sdfr}
133177633Sdfr
134177633Sdfrvoid
135177633Sdfr__xprt_unregister_unlocked(SVCXPRT *xprt)
136177633Sdfr{
137177633Sdfr	__xprt_do_unregister(xprt, FALSE);
138177633Sdfr}
139177633Sdfr
140177633Sdfr/*
141177633Sdfr * De-activate a transport handle.
142177633Sdfr */
143177633Sdfrstatic void
144177633Sdfr__xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
145177633Sdfr{
146177633Sdfr	SVCPOOL *pool = xprt->xp_pool;
147177633Sdfr
148177633Sdfr	//__svc_generic_cleanup(xprt);
149177633Sdfr
150177633Sdfr	if (dolock)
151177633Sdfr		mtx_lock(&pool->sp_lock);
152177633Sdfr
153177633Sdfr	if (xprt->xp_active) {
154177633Sdfr		TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
155177633Sdfr		xprt->xp_active = FALSE;
156177633Sdfr	}
157177633Sdfr	TAILQ_REMOVE(&pool->sp_xlist, xprt, xp_link);
158177633Sdfr	xprt->xp_registered = FALSE;
159177633Sdfr
160177633Sdfr	if (dolock)
161177633Sdfr		mtx_unlock(&pool->sp_lock);
162177633Sdfr}
163177633Sdfr
164177633Sdfrvoid
165177633Sdfrxprt_active(SVCXPRT *xprt)
166177633Sdfr{
167177633Sdfr	SVCPOOL *pool = xprt->xp_pool;
168177633Sdfr
169177633Sdfr	mtx_lock(&pool->sp_lock);
170177633Sdfr
171177633Sdfr	if (!xprt->xp_active) {
172177633Sdfr		TAILQ_INSERT_TAIL(&pool->sp_active, xprt, xp_alink);
173177633Sdfr		xprt->xp_active = TRUE;
174177633Sdfr	}
175177633Sdfr	wakeup(&pool->sp_active);
176177633Sdfr
177177633Sdfr	mtx_unlock(&pool->sp_lock);
178177633Sdfr}
179177633Sdfr
180177633Sdfrvoid
181177633Sdfrxprt_inactive(SVCXPRT *xprt)
182177633Sdfr{
183177633Sdfr	SVCPOOL *pool = xprt->xp_pool;
184177633Sdfr
185177633Sdfr	mtx_lock(&pool->sp_lock);
186177633Sdfr
187177633Sdfr	if (xprt->xp_active) {
188177633Sdfr		TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
189177633Sdfr		xprt->xp_active = FALSE;
190177633Sdfr	}
191177633Sdfr	wakeup(&pool->sp_active);
192177633Sdfr
193177633Sdfr	mtx_unlock(&pool->sp_lock);
194177633Sdfr}
195177633Sdfr
196177633Sdfr/*
197177633Sdfr * Add a service program to the callout list.
198177633Sdfr * The dispatch routine will be called when a rpc request for this
199177633Sdfr * program number comes in.
200177633Sdfr */
201177633Sdfrbool_t
202177633Sdfrsvc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
203177633Sdfr    void (*dispatch)(struct svc_req *, SVCXPRT *),
204177633Sdfr    const struct netconfig *nconf)
205177633Sdfr{
206177633Sdfr	SVCPOOL *pool = xprt->xp_pool;
207177633Sdfr	struct svc_callout *s;
208177633Sdfr	char *netid = NULL;
209177633Sdfr	int flag = 0;
210177633Sdfr
211177633Sdfr/* VARIABLES PROTECTED BY svc_lock: s, svc_head */
212177633Sdfr
213177633Sdfr	if (xprt->xp_netid) {
214177633Sdfr		netid = strdup(xprt->xp_netid, M_RPC);
215177633Sdfr		flag = 1;
216177633Sdfr	} else if (nconf && nconf->nc_netid) {
217177633Sdfr		netid = strdup(nconf->nc_netid, M_RPC);
218177633Sdfr		flag = 1;
219177633Sdfr	} /* must have been created with svc_raw_create */
220177633Sdfr	if ((netid == NULL) && (flag == 1)) {
221177633Sdfr		return (FALSE);
222177633Sdfr	}
223177633Sdfr
224177633Sdfr	mtx_lock(&pool->sp_lock);
225177633Sdfr	if ((s = svc_find(pool, prog, vers, netid)) != NULL) {
226177633Sdfr		if (netid)
227177633Sdfr			free(netid, M_RPC);
228177633Sdfr		if (s->sc_dispatch == dispatch)
229177633Sdfr			goto rpcb_it; /* he is registering another xptr */
230177633Sdfr		mtx_unlock(&pool->sp_lock);
231177633Sdfr		return (FALSE);
232177633Sdfr	}
233177633Sdfr	s = malloc(sizeof (struct svc_callout), M_RPC, M_NOWAIT);
234177633Sdfr	if (s == NULL) {
235177633Sdfr		if (netid)
236177633Sdfr			free(netid, M_RPC);
237177633Sdfr		mtx_unlock(&pool->sp_lock);
238177633Sdfr		return (FALSE);
239177633Sdfr	}
240177633Sdfr
241177633Sdfr	s->sc_prog = prog;
242177633Sdfr	s->sc_vers = vers;
243177633Sdfr	s->sc_dispatch = dispatch;
244177633Sdfr	s->sc_netid = netid;
245177633Sdfr	TAILQ_INSERT_TAIL(&pool->sp_callouts, s, sc_link);
246177633Sdfr
247177633Sdfr	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
248177633Sdfr		((SVCXPRT *) xprt)->xp_netid = strdup(netid, M_RPC);
249177633Sdfr
250177633Sdfrrpcb_it:
251177633Sdfr	mtx_unlock(&pool->sp_lock);
252177633Sdfr	/* now register the information with the local binder service */
253177633Sdfr	if (nconf) {
254177633Sdfr		bool_t dummy;
255177633Sdfr		struct netconfig tnc;
256177633Sdfr		tnc = *nconf;
257177633Sdfr		dummy = rpcb_set(prog, vers, &tnc,
258177633Sdfr		    &((SVCXPRT *) xprt)->xp_ltaddr);
259177633Sdfr		return (dummy);
260177633Sdfr	}
261177633Sdfr	return (TRUE);
262177633Sdfr}
263177633Sdfr
264177633Sdfr/*
265177633Sdfr * Remove a service program from the callout list.
266177633Sdfr */
267177633Sdfrvoid
268177633Sdfrsvc_unreg(SVCPOOL *pool, const rpcprog_t prog, const rpcvers_t vers)
269177633Sdfr{
270177633Sdfr	struct svc_callout *s;
271177633Sdfr
272177633Sdfr	/* unregister the information anyway */
273177633Sdfr	(void) rpcb_unset(prog, vers, NULL);
274177633Sdfr	mtx_lock(&pool->sp_lock);
275177633Sdfr	while ((s = svc_find(pool, prog, vers, NULL)) != NULL) {
276177633Sdfr		TAILQ_REMOVE(&pool->sp_callouts, s, sc_link);
277177633Sdfr		if (s->sc_netid)
278177633Sdfr			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
279177633Sdfr		mem_free(s, sizeof (struct svc_callout));
280177633Sdfr	}
281177633Sdfr	mtx_unlock(&pool->sp_lock);
282177633Sdfr}
283177633Sdfr
284177633Sdfr/* ********************** CALLOUT list related stuff ************* */
285177633Sdfr
286177633Sdfr/*
287177633Sdfr * Search the callout list for a program number, return the callout
288177633Sdfr * struct.
289177633Sdfr */
290177633Sdfrstatic struct svc_callout *
291177633Sdfrsvc_find(SVCPOOL *pool, rpcprog_t prog, rpcvers_t vers, char *netid)
292177633Sdfr{
293177633Sdfr	struct svc_callout *s;
294177633Sdfr
295177633Sdfr	mtx_assert(&pool->sp_lock, MA_OWNED);
296177633Sdfr	TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
297177633Sdfr		if (s->sc_prog == prog && s->sc_vers == vers
298177633Sdfr		    && (netid == NULL || s->sc_netid == NULL ||
299177633Sdfr			strcmp(netid, s->sc_netid) == 0))
300177633Sdfr			break;
301177633Sdfr	}
302177633Sdfr
303177633Sdfr	return (s);
304177633Sdfr}
305177633Sdfr
306177633Sdfr/* ******************* REPLY GENERATION ROUTINES  ************ */
307177633Sdfr
308177633Sdfr/*
309177633Sdfr * Send a reply to an rpc request
310177633Sdfr */
311177633Sdfrbool_t
312177633Sdfrsvc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, void * xdr_location)
313177633Sdfr{
314177633Sdfr	struct rpc_msg rply;
315177633Sdfr
316177633Sdfr	rply.rm_direction = REPLY;
317177633Sdfr	rply.rm_reply.rp_stat = MSG_ACCEPTED;
318177633Sdfr	rply.acpted_rply.ar_verf = xprt->xp_verf;
319177633Sdfr	rply.acpted_rply.ar_stat = SUCCESS;
320177633Sdfr	rply.acpted_rply.ar_results.where = xdr_location;
321177633Sdfr	rply.acpted_rply.ar_results.proc = xdr_results;
322177633Sdfr
323177633Sdfr	return (SVC_REPLY(xprt, &rply));
324177633Sdfr}
325177633Sdfr
326177633Sdfr/*
327177633Sdfr * No procedure error reply
328177633Sdfr */
329177633Sdfrvoid
330177633Sdfrsvcerr_noproc(SVCXPRT *xprt)
331177633Sdfr{
332177633Sdfr	struct rpc_msg rply;
333177633Sdfr
334177633Sdfr	rply.rm_direction = REPLY;
335177633Sdfr	rply.rm_reply.rp_stat = MSG_ACCEPTED;
336177633Sdfr	rply.acpted_rply.ar_verf = xprt->xp_verf;
337177633Sdfr	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
338177633Sdfr
339177633Sdfr	SVC_REPLY(xprt, &rply);
340177633Sdfr}
341177633Sdfr
342177633Sdfr/*
343177633Sdfr * Can't decode args error reply
344177633Sdfr */
345177633Sdfrvoid
346177633Sdfrsvcerr_decode(SVCXPRT *xprt)
347177633Sdfr{
348177633Sdfr	struct rpc_msg rply;
349177633Sdfr
350177633Sdfr	rply.rm_direction = REPLY;
351177633Sdfr	rply.rm_reply.rp_stat = MSG_ACCEPTED;
352177633Sdfr	rply.acpted_rply.ar_verf = xprt->xp_verf;
353177633Sdfr	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
354177633Sdfr
355177633Sdfr	SVC_REPLY(xprt, &rply);
356177633Sdfr}
357177633Sdfr
358177633Sdfr/*
359177633Sdfr * Some system error
360177633Sdfr */
361177633Sdfrvoid
362177633Sdfrsvcerr_systemerr(SVCXPRT *xprt)
363177633Sdfr{
364177633Sdfr	struct rpc_msg rply;
365177633Sdfr
366177633Sdfr	rply.rm_direction = REPLY;
367177633Sdfr	rply.rm_reply.rp_stat = MSG_ACCEPTED;
368177633Sdfr	rply.acpted_rply.ar_verf = xprt->xp_verf;
369177633Sdfr	rply.acpted_rply.ar_stat = SYSTEM_ERR;
370177633Sdfr
371177633Sdfr	SVC_REPLY(xprt, &rply);
372177633Sdfr}
373177633Sdfr
374177633Sdfr/*
375177633Sdfr * Authentication error reply
376177633Sdfr */
377177633Sdfrvoid
378177633Sdfrsvcerr_auth(SVCXPRT *xprt, enum auth_stat why)
379177633Sdfr{
380177633Sdfr	struct rpc_msg rply;
381177633Sdfr
382177633Sdfr	rply.rm_direction = REPLY;
383177633Sdfr	rply.rm_reply.rp_stat = MSG_DENIED;
384177633Sdfr	rply.rjcted_rply.rj_stat = AUTH_ERROR;
385177633Sdfr	rply.rjcted_rply.rj_why = why;
386177633Sdfr
387177633Sdfr	SVC_REPLY(xprt, &rply);
388177633Sdfr}
389177633Sdfr
390177633Sdfr/*
391177633Sdfr * Auth too weak error reply
392177633Sdfr */
393177633Sdfrvoid
394177633Sdfrsvcerr_weakauth(SVCXPRT *xprt)
395177633Sdfr{
396177633Sdfr
397177633Sdfr	svcerr_auth(xprt, AUTH_TOOWEAK);
398177633Sdfr}
399177633Sdfr
400177633Sdfr/*
401177633Sdfr * Program unavailable error reply
402177633Sdfr */
403177633Sdfrvoid
404177633Sdfrsvcerr_noprog(SVCXPRT *xprt)
405177633Sdfr{
406177633Sdfr	struct rpc_msg rply;
407177633Sdfr
408177633Sdfr	rply.rm_direction = REPLY;
409177633Sdfr	rply.rm_reply.rp_stat = MSG_ACCEPTED;
410177633Sdfr	rply.acpted_rply.ar_verf = xprt->xp_verf;
411177633Sdfr	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
412177633Sdfr
413177633Sdfr	SVC_REPLY(xprt, &rply);
414177633Sdfr}
415177633Sdfr
416177633Sdfr/*
417177633Sdfr * Program version mismatch error reply
418177633Sdfr */
419177633Sdfrvoid
420177633Sdfrsvcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
421177633Sdfr{
422177633Sdfr	struct rpc_msg rply;
423177633Sdfr
424177633Sdfr	rply.rm_direction = REPLY;
425177633Sdfr	rply.rm_reply.rp_stat = MSG_ACCEPTED;
426177633Sdfr	rply.acpted_rply.ar_verf = xprt->xp_verf;
427177633Sdfr	rply.acpted_rply.ar_stat = PROG_MISMATCH;
428177633Sdfr	rply.acpted_rply.ar_vers.low = (uint32_t)low_vers;
429177633Sdfr	rply.acpted_rply.ar_vers.high = (uint32_t)high_vers;
430177633Sdfr
431177633Sdfr	SVC_REPLY(xprt, &rply);
432177633Sdfr}
433177633Sdfr
434177633Sdfr/* ******************* SERVER INPUT STUFF ******************* */
435177633Sdfr
436177633Sdfr/*
437177633Sdfr * Get server side input from some transport.
438177633Sdfr *
439177633Sdfr * Statement of authentication parameters management:
440177633Sdfr * This function owns and manages all authentication parameters, specifically
441177633Sdfr * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
442177633Sdfr * the "cooked" credentials (rqst->rq_clntcred).
443177633Sdfr * In-kernel, we represent non-trivial cooked creds with struct ucred.
444177633Sdfr * In all events, all three parameters are freed upon exit from this routine.
445177633Sdfr * The storage is trivially management on the call stack in user land, but
446177633Sdfr * is mallocated in kernel land.
447177633Sdfr */
448177633Sdfr
449177633Sdfrstatic void
450177633Sdfrsvc_getreq(SVCXPRT *xprt)
451177633Sdfr{
452177633Sdfr	SVCPOOL *pool = xprt->xp_pool;
453177633Sdfr	struct svc_req r;
454177633Sdfr	struct rpc_msg msg;
455177633Sdfr	int prog_found;
456177633Sdfr	rpcvers_t low_vers;
457177633Sdfr	rpcvers_t high_vers;
458177633Sdfr	enum xprt_stat stat;
459177633Sdfr	char cred_area[2*MAX_AUTH_BYTES + sizeof(struct xucred)];
460177633Sdfr
461177633Sdfr	msg.rm_call.cb_cred.oa_base = cred_area;
462177633Sdfr	msg.rm_call.cb_verf.oa_base = &cred_area[MAX_AUTH_BYTES];
463177633Sdfr	r.rq_clntcred = &cred_area[2*MAX_AUTH_BYTES];
464177633Sdfr
465177633Sdfr	/* now receive msgs from xprtprt (support batch calls) */
466177633Sdfr	do {
467177633Sdfr		if (SVC_RECV(xprt, &msg)) {
468177633Sdfr
469177633Sdfr			/* now find the exported program and call it */
470177633Sdfr			struct svc_callout *s;
471177633Sdfr			enum auth_stat why;
472177633Sdfr
473177633Sdfr			r.rq_xprt = xprt;
474177633Sdfr			r.rq_prog = msg.rm_call.cb_prog;
475177633Sdfr			r.rq_vers = msg.rm_call.cb_vers;
476177633Sdfr			r.rq_proc = msg.rm_call.cb_proc;
477177633Sdfr			r.rq_cred = msg.rm_call.cb_cred;
478177633Sdfr			/* first authenticate the message */
479177633Sdfr			if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
480177633Sdfr				svcerr_auth(xprt, why);
481177633Sdfr				goto call_done;
482177633Sdfr			}
483177633Sdfr			/* now match message with a registered service*/
484177633Sdfr			prog_found = FALSE;
485177633Sdfr			low_vers = (rpcvers_t) -1L;
486177633Sdfr			high_vers = (rpcvers_t) 0L;
487177633Sdfr			TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
488177633Sdfr				if (s->sc_prog == r.rq_prog) {
489177633Sdfr					if (s->sc_vers == r.rq_vers) {
490177633Sdfr						(*s->sc_dispatch)(&r, xprt);
491177633Sdfr						goto call_done;
492177633Sdfr					}  /* found correct version */
493177633Sdfr					prog_found = TRUE;
494177633Sdfr					if (s->sc_vers < low_vers)
495177633Sdfr						low_vers = s->sc_vers;
496177633Sdfr					if (s->sc_vers > high_vers)
497177633Sdfr						high_vers = s->sc_vers;
498177633Sdfr				}   /* found correct program */
499177633Sdfr			}
500177633Sdfr			/*
501177633Sdfr			 * if we got here, the program or version
502177633Sdfr			 * is not served ...
503177633Sdfr			 */
504177633Sdfr			if (prog_found)
505177633Sdfr				svcerr_progvers(xprt, low_vers, high_vers);
506177633Sdfr			else
507177633Sdfr				svcerr_noprog(xprt);
508177633Sdfr			/* Fall through to ... */
509177633Sdfr		}
510177633Sdfr		/*
511177633Sdfr		 * Check if the xprt has been disconnected in a
512177633Sdfr		 * recursive call in the service dispatch routine.
513177633Sdfr		 * If so, then break.
514177633Sdfr		 */
515177633Sdfr		mtx_lock(&pool->sp_lock);
516177633Sdfr		if (!xprt->xp_registered) {
517177633Sdfr			mtx_unlock(&pool->sp_lock);
518177633Sdfr			break;
519177633Sdfr		}
520177633Sdfr		mtx_unlock(&pool->sp_lock);
521177633Sdfrcall_done:
522177633Sdfr		if ((stat = SVC_STAT(xprt)) == XPRT_DIED) {
523177633Sdfr			SVC_DESTROY(xprt);
524177633Sdfr			break;
525177633Sdfr		}
526177633Sdfr	} while (stat == XPRT_MOREREQS);
527177633Sdfr}
528177633Sdfr
529177633Sdfrvoid
530177633Sdfrsvc_run(SVCPOOL *pool)
531177633Sdfr{
532177633Sdfr	SVCXPRT *xprt;
533177633Sdfr	int error;
534177633Sdfr
535177633Sdfr	mtx_lock(&pool->sp_lock);
536177633Sdfr
537177633Sdfr	pool->sp_exited = FALSE;
538177633Sdfr
539177633Sdfr	while (!pool->sp_exited) {
540177633Sdfr		xprt = TAILQ_FIRST(&pool->sp_active);
541177633Sdfr		if (!xprt) {
542177633Sdfr			error = msleep(&pool->sp_active, &pool->sp_lock, PCATCH,
543177633Sdfr			    "rpcsvc", 0);
544177633Sdfr			if (error)
545177633Sdfr				break;
546177633Sdfr			continue;
547177633Sdfr		}
548177633Sdfr
549177633Sdfr		/*
550177633Sdfr		 * Move this transport to the end to ensure fairness
551177633Sdfr		 * when multiple transports are active. If this was
552177633Sdfr		 * the last queued request, svc_getreq will end up
553177633Sdfr		 * calling xprt_inactive to remove from the active
554177633Sdfr		 * list.
555177633Sdfr		 */
556177633Sdfr		TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
557177633Sdfr		TAILQ_INSERT_TAIL(&pool->sp_active, xprt, xp_alink);
558177633Sdfr
559177633Sdfr		mtx_unlock(&pool->sp_lock);
560177633Sdfr		svc_getreq(xprt);
561177633Sdfr		mtx_lock(&pool->sp_lock);
562177633Sdfr	}
563177633Sdfr
564177633Sdfr	mtx_unlock(&pool->sp_lock);
565177633Sdfr}
566177633Sdfr
567177633Sdfrvoid
568177633Sdfrsvc_exit(SVCPOOL *pool)
569177633Sdfr{
570177633Sdfr	mtx_lock(&pool->sp_lock);
571177633Sdfr	pool->sp_exited = TRUE;
572177633Sdfr	wakeup(&pool->sp_active);
573177633Sdfr	mtx_unlock(&pool->sp_lock);
574177633Sdfr}
575