xref: /freebsd/sys/rpc/svc.c (revision dfdcada31e7924c832024404c6a09a2db04e397e)
1dfdcada3SDoug Rabson /*	$NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $	*/
2dfdcada3SDoug Rabson 
3dfdcada3SDoug Rabson /*
4dfdcada3SDoug Rabson  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5dfdcada3SDoug Rabson  * unrestricted use provided that this legend is included on all tape
6dfdcada3SDoug Rabson  * media and as a part of the software program in whole or part.  Users
7dfdcada3SDoug Rabson  * may copy or modify Sun RPC without charge, but are not authorized
8dfdcada3SDoug Rabson  * to license or distribute it to anyone else except as part of a product or
9dfdcada3SDoug Rabson  * program developed by the user.
10dfdcada3SDoug Rabson  *
11dfdcada3SDoug Rabson  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12dfdcada3SDoug Rabson  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13dfdcada3SDoug Rabson  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14dfdcada3SDoug Rabson  *
15dfdcada3SDoug Rabson  * Sun RPC is provided with no support and without any obligation on the
16dfdcada3SDoug Rabson  * part of Sun Microsystems, Inc. to assist in its use, correction,
17dfdcada3SDoug Rabson  * modification or enhancement.
18dfdcada3SDoug Rabson  *
19dfdcada3SDoug Rabson  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20dfdcada3SDoug Rabson  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21dfdcada3SDoug Rabson  * OR ANY PART THEREOF.
22dfdcada3SDoug Rabson  *
23dfdcada3SDoug Rabson  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24dfdcada3SDoug Rabson  * or profits or other special, indirect and consequential damages, even if
25dfdcada3SDoug Rabson  * Sun has been advised of the possibility of such damages.
26dfdcada3SDoug Rabson  *
27dfdcada3SDoug Rabson  * Sun Microsystems, Inc.
28dfdcada3SDoug Rabson  * 2550 Garcia Avenue
29dfdcada3SDoug Rabson  * Mountain View, California  94043
30dfdcada3SDoug Rabson  */
31dfdcada3SDoug Rabson 
32dfdcada3SDoug Rabson #if defined(LIBC_SCCS) && !defined(lint)
33dfdcada3SDoug Rabson static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
34dfdcada3SDoug Rabson static char *sccsid = "@(#)svc.c	2.4 88/08/11 4.0 RPCSRC";
35dfdcada3SDoug Rabson #endif
36dfdcada3SDoug Rabson #include <sys/cdefs.h>
37dfdcada3SDoug Rabson __FBSDID("$FreeBSD$");
38dfdcada3SDoug Rabson 
39dfdcada3SDoug Rabson /*
40dfdcada3SDoug Rabson  * svc.c, Server-side remote procedure call interface.
41dfdcada3SDoug Rabson  *
42dfdcada3SDoug Rabson  * There are two sets of procedures here.  The xprt routines are
43dfdcada3SDoug Rabson  * for handling transport handles.  The svc routines handle the
44dfdcada3SDoug Rabson  * list of service routines.
45dfdcada3SDoug Rabson  *
46dfdcada3SDoug Rabson  * Copyright (C) 1984, Sun Microsystems, Inc.
47dfdcada3SDoug Rabson  */
48dfdcada3SDoug Rabson 
49dfdcada3SDoug Rabson #include <sys/param.h>
50dfdcada3SDoug Rabson #include <sys/lock.h>
51dfdcada3SDoug Rabson #include <sys/kernel.h>
52dfdcada3SDoug Rabson #include <sys/malloc.h>
53dfdcada3SDoug Rabson #include <sys/mutex.h>
54dfdcada3SDoug Rabson #include <sys/queue.h>
55dfdcada3SDoug Rabson #include <sys/systm.h>
56dfdcada3SDoug Rabson #include <sys/ucred.h>
57dfdcada3SDoug Rabson 
58dfdcada3SDoug Rabson #include <rpc/rpc.h>
59dfdcada3SDoug Rabson #include <rpc/rpcb_clnt.h>
60dfdcada3SDoug Rabson 
61dfdcada3SDoug Rabson #include "rpc_com.h"
62dfdcada3SDoug Rabson 
63dfdcada3SDoug Rabson #define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
64dfdcada3SDoug Rabson #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
65dfdcada3SDoug Rabson 
66dfdcada3SDoug Rabson static struct svc_callout *svc_find(SVCPOOL *pool, rpcprog_t, rpcvers_t,
67dfdcada3SDoug Rabson     char *);
68dfdcada3SDoug Rabson static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock);
69dfdcada3SDoug Rabson 
70dfdcada3SDoug Rabson /* ***************  SVCXPRT related stuff **************** */
71dfdcada3SDoug Rabson 
72dfdcada3SDoug Rabson SVCPOOL*
73dfdcada3SDoug Rabson svcpool_create(void)
74dfdcada3SDoug Rabson {
75dfdcada3SDoug Rabson 	SVCPOOL *pool;
76dfdcada3SDoug Rabson 
77dfdcada3SDoug Rabson 	pool = malloc(sizeof(SVCPOOL), M_RPC, M_WAITOK|M_ZERO);
78dfdcada3SDoug Rabson 
79dfdcada3SDoug Rabson 	mtx_init(&pool->sp_lock, "sp_lock", NULL, MTX_DEF);
80dfdcada3SDoug Rabson 	TAILQ_INIT(&pool->sp_xlist);
81dfdcada3SDoug Rabson 	TAILQ_INIT(&pool->sp_active);
82dfdcada3SDoug Rabson 	TAILQ_INIT(&pool->sp_callouts);
83dfdcada3SDoug Rabson 
84dfdcada3SDoug Rabson 	return pool;
85dfdcada3SDoug Rabson }
86dfdcada3SDoug Rabson 
87dfdcada3SDoug Rabson void
88dfdcada3SDoug Rabson svcpool_destroy(SVCPOOL *pool)
89dfdcada3SDoug Rabson {
90dfdcada3SDoug Rabson 	SVCXPRT *xprt;
91dfdcada3SDoug Rabson 	struct svc_callout *s;
92dfdcada3SDoug Rabson 
93dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
94dfdcada3SDoug Rabson 
95dfdcada3SDoug Rabson 	while (TAILQ_FIRST(&pool->sp_xlist)) {
96dfdcada3SDoug Rabson 		xprt = TAILQ_FIRST(&pool->sp_xlist);
97dfdcada3SDoug Rabson 		mtx_unlock(&pool->sp_lock);
98dfdcada3SDoug Rabson 		SVC_DESTROY(xprt);
99dfdcada3SDoug Rabson 		mtx_lock(&pool->sp_lock);
100dfdcada3SDoug Rabson 	}
101dfdcada3SDoug Rabson 
102dfdcada3SDoug Rabson 	while (TAILQ_FIRST(&pool->sp_callouts)) {
103dfdcada3SDoug Rabson 		s = TAILQ_FIRST(&pool->sp_callouts);
104dfdcada3SDoug Rabson 		mtx_unlock(&pool->sp_lock);
105dfdcada3SDoug Rabson 		svc_unreg(pool, s->sc_prog, s->sc_vers);
106dfdcada3SDoug Rabson 		mtx_lock(&pool->sp_lock);
107dfdcada3SDoug Rabson 	}
108dfdcada3SDoug Rabson 
109dfdcada3SDoug Rabson 	mtx_destroy(&pool->sp_lock);
110dfdcada3SDoug Rabson 	free(pool, M_RPC);
111dfdcada3SDoug Rabson }
112dfdcada3SDoug Rabson 
113dfdcada3SDoug Rabson /*
114dfdcada3SDoug Rabson  * Activate a transport handle.
115dfdcada3SDoug Rabson  */
116dfdcada3SDoug Rabson void
117dfdcada3SDoug Rabson xprt_register(SVCXPRT *xprt)
118dfdcada3SDoug Rabson {
119dfdcada3SDoug Rabson 	SVCPOOL *pool = xprt->xp_pool;
120dfdcada3SDoug Rabson 
121dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
122dfdcada3SDoug Rabson 	xprt->xp_registered = TRUE;
123dfdcada3SDoug Rabson 	xprt->xp_active = FALSE;
124dfdcada3SDoug Rabson 	TAILQ_INSERT_TAIL(&pool->sp_xlist, xprt, xp_link);
125dfdcada3SDoug Rabson 	mtx_unlock(&pool->sp_lock);
126dfdcada3SDoug Rabson }
127dfdcada3SDoug Rabson 
128dfdcada3SDoug Rabson void
129dfdcada3SDoug Rabson xprt_unregister(SVCXPRT *xprt)
130dfdcada3SDoug Rabson {
131dfdcada3SDoug Rabson 	__xprt_do_unregister(xprt, TRUE);
132dfdcada3SDoug Rabson }
133dfdcada3SDoug Rabson 
134dfdcada3SDoug Rabson void
135dfdcada3SDoug Rabson __xprt_unregister_unlocked(SVCXPRT *xprt)
136dfdcada3SDoug Rabson {
137dfdcada3SDoug Rabson 	__xprt_do_unregister(xprt, FALSE);
138dfdcada3SDoug Rabson }
139dfdcada3SDoug Rabson 
140dfdcada3SDoug Rabson /*
141dfdcada3SDoug Rabson  * De-activate a transport handle.
142dfdcada3SDoug Rabson  */
143dfdcada3SDoug Rabson static void
144dfdcada3SDoug Rabson __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
145dfdcada3SDoug Rabson {
146dfdcada3SDoug Rabson 	SVCPOOL *pool = xprt->xp_pool;
147dfdcada3SDoug Rabson 
148dfdcada3SDoug Rabson 	//__svc_generic_cleanup(xprt);
149dfdcada3SDoug Rabson 
150dfdcada3SDoug Rabson 	if (dolock)
151dfdcada3SDoug Rabson 		mtx_lock(&pool->sp_lock);
152dfdcada3SDoug Rabson 
153dfdcada3SDoug Rabson 	if (xprt->xp_active) {
154dfdcada3SDoug Rabson 		TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
155dfdcada3SDoug Rabson 		xprt->xp_active = FALSE;
156dfdcada3SDoug Rabson 	}
157dfdcada3SDoug Rabson 	TAILQ_REMOVE(&pool->sp_xlist, xprt, xp_link);
158dfdcada3SDoug Rabson 	xprt->xp_registered = FALSE;
159dfdcada3SDoug Rabson 
160dfdcada3SDoug Rabson 	if (dolock)
161dfdcada3SDoug Rabson 		mtx_unlock(&pool->sp_lock);
162dfdcada3SDoug Rabson }
163dfdcada3SDoug Rabson 
164dfdcada3SDoug Rabson void
165dfdcada3SDoug Rabson xprt_active(SVCXPRT *xprt)
166dfdcada3SDoug Rabson {
167dfdcada3SDoug Rabson 	SVCPOOL *pool = xprt->xp_pool;
168dfdcada3SDoug Rabson 
169dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
170dfdcada3SDoug Rabson 
171dfdcada3SDoug Rabson 	if (!xprt->xp_active) {
172dfdcada3SDoug Rabson 		TAILQ_INSERT_TAIL(&pool->sp_active, xprt, xp_alink);
173dfdcada3SDoug Rabson 		xprt->xp_active = TRUE;
174dfdcada3SDoug Rabson 	}
175dfdcada3SDoug Rabson 	wakeup(&pool->sp_active);
176dfdcada3SDoug Rabson 
177dfdcada3SDoug Rabson 	mtx_unlock(&pool->sp_lock);
178dfdcada3SDoug Rabson }
179dfdcada3SDoug Rabson 
180dfdcada3SDoug Rabson void
181dfdcada3SDoug Rabson xprt_inactive(SVCXPRT *xprt)
182dfdcada3SDoug Rabson {
183dfdcada3SDoug Rabson 	SVCPOOL *pool = xprt->xp_pool;
184dfdcada3SDoug Rabson 
185dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
186dfdcada3SDoug Rabson 
187dfdcada3SDoug Rabson 	if (xprt->xp_active) {
188dfdcada3SDoug Rabson 		TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
189dfdcada3SDoug Rabson 		xprt->xp_active = FALSE;
190dfdcada3SDoug Rabson 	}
191dfdcada3SDoug Rabson 	wakeup(&pool->sp_active);
192dfdcada3SDoug Rabson 
193dfdcada3SDoug Rabson 	mtx_unlock(&pool->sp_lock);
194dfdcada3SDoug Rabson }
195dfdcada3SDoug Rabson 
196dfdcada3SDoug Rabson /*
197dfdcada3SDoug Rabson  * Add a service program to the callout list.
198dfdcada3SDoug Rabson  * The dispatch routine will be called when a rpc request for this
199dfdcada3SDoug Rabson  * program number comes in.
200dfdcada3SDoug Rabson  */
201dfdcada3SDoug Rabson bool_t
202dfdcada3SDoug Rabson svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
203dfdcada3SDoug Rabson     void (*dispatch)(struct svc_req *, SVCXPRT *),
204dfdcada3SDoug Rabson     const struct netconfig *nconf)
205dfdcada3SDoug Rabson {
206dfdcada3SDoug Rabson 	SVCPOOL *pool = xprt->xp_pool;
207dfdcada3SDoug Rabson 	struct svc_callout *s;
208dfdcada3SDoug Rabson 	char *netid = NULL;
209dfdcada3SDoug Rabson 	int flag = 0;
210dfdcada3SDoug Rabson 
211dfdcada3SDoug Rabson /* VARIABLES PROTECTED BY svc_lock: s, svc_head */
212dfdcada3SDoug Rabson 
213dfdcada3SDoug Rabson 	if (xprt->xp_netid) {
214dfdcada3SDoug Rabson 		netid = strdup(xprt->xp_netid, M_RPC);
215dfdcada3SDoug Rabson 		flag = 1;
216dfdcada3SDoug Rabson 	} else if (nconf && nconf->nc_netid) {
217dfdcada3SDoug Rabson 		netid = strdup(nconf->nc_netid, M_RPC);
218dfdcada3SDoug Rabson 		flag = 1;
219dfdcada3SDoug Rabson 	} /* must have been created with svc_raw_create */
220dfdcada3SDoug Rabson 	if ((netid == NULL) && (flag == 1)) {
221dfdcada3SDoug Rabson 		return (FALSE);
222dfdcada3SDoug Rabson 	}
223dfdcada3SDoug Rabson 
224dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
225dfdcada3SDoug Rabson 	if ((s = svc_find(pool, prog, vers, netid)) != NULL) {
226dfdcada3SDoug Rabson 		if (netid)
227dfdcada3SDoug Rabson 			free(netid, M_RPC);
228dfdcada3SDoug Rabson 		if (s->sc_dispatch == dispatch)
229dfdcada3SDoug Rabson 			goto rpcb_it; /* he is registering another xptr */
230dfdcada3SDoug Rabson 		mtx_unlock(&pool->sp_lock);
231dfdcada3SDoug Rabson 		return (FALSE);
232dfdcada3SDoug Rabson 	}
233dfdcada3SDoug Rabson 	s = malloc(sizeof (struct svc_callout), M_RPC, M_NOWAIT);
234dfdcada3SDoug Rabson 	if (s == NULL) {
235dfdcada3SDoug Rabson 		if (netid)
236dfdcada3SDoug Rabson 			free(netid, M_RPC);
237dfdcada3SDoug Rabson 		mtx_unlock(&pool->sp_lock);
238dfdcada3SDoug Rabson 		return (FALSE);
239dfdcada3SDoug Rabson 	}
240dfdcada3SDoug Rabson 
241dfdcada3SDoug Rabson 	s->sc_prog = prog;
242dfdcada3SDoug Rabson 	s->sc_vers = vers;
243dfdcada3SDoug Rabson 	s->sc_dispatch = dispatch;
244dfdcada3SDoug Rabson 	s->sc_netid = netid;
245dfdcada3SDoug Rabson 	TAILQ_INSERT_TAIL(&pool->sp_callouts, s, sc_link);
246dfdcada3SDoug Rabson 
247dfdcada3SDoug Rabson 	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
248dfdcada3SDoug Rabson 		((SVCXPRT *) xprt)->xp_netid = strdup(netid, M_RPC);
249dfdcada3SDoug Rabson 
250dfdcada3SDoug Rabson rpcb_it:
251dfdcada3SDoug Rabson 	mtx_unlock(&pool->sp_lock);
252dfdcada3SDoug Rabson 	/* now register the information with the local binder service */
253dfdcada3SDoug Rabson 	if (nconf) {
254dfdcada3SDoug Rabson 		bool_t dummy;
255dfdcada3SDoug Rabson 		struct netconfig tnc;
256dfdcada3SDoug Rabson 		tnc = *nconf;
257dfdcada3SDoug Rabson 		dummy = rpcb_set(prog, vers, &tnc,
258dfdcada3SDoug Rabson 		    &((SVCXPRT *) xprt)->xp_ltaddr);
259dfdcada3SDoug Rabson 		return (dummy);
260dfdcada3SDoug Rabson 	}
261dfdcada3SDoug Rabson 	return (TRUE);
262dfdcada3SDoug Rabson }
263dfdcada3SDoug Rabson 
264dfdcada3SDoug Rabson /*
265dfdcada3SDoug Rabson  * Remove a service program from the callout list.
266dfdcada3SDoug Rabson  */
267dfdcada3SDoug Rabson void
268dfdcada3SDoug Rabson svc_unreg(SVCPOOL *pool, const rpcprog_t prog, const rpcvers_t vers)
269dfdcada3SDoug Rabson {
270dfdcada3SDoug Rabson 	struct svc_callout *s;
271dfdcada3SDoug Rabson 
272dfdcada3SDoug Rabson 	/* unregister the information anyway */
273dfdcada3SDoug Rabson 	(void) rpcb_unset(prog, vers, NULL);
274dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
275dfdcada3SDoug Rabson 	while ((s = svc_find(pool, prog, vers, NULL)) != NULL) {
276dfdcada3SDoug Rabson 		TAILQ_REMOVE(&pool->sp_callouts, s, sc_link);
277dfdcada3SDoug Rabson 		if (s->sc_netid)
278dfdcada3SDoug Rabson 			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
279dfdcada3SDoug Rabson 		mem_free(s, sizeof (struct svc_callout));
280dfdcada3SDoug Rabson 	}
281dfdcada3SDoug Rabson 	mtx_unlock(&pool->sp_lock);
282dfdcada3SDoug Rabson }
283dfdcada3SDoug Rabson 
284dfdcada3SDoug Rabson /* ********************** CALLOUT list related stuff ************* */
285dfdcada3SDoug Rabson 
286dfdcada3SDoug Rabson /*
287dfdcada3SDoug Rabson  * Search the callout list for a program number, return the callout
288dfdcada3SDoug Rabson  * struct.
289dfdcada3SDoug Rabson  */
290dfdcada3SDoug Rabson static struct svc_callout *
291dfdcada3SDoug Rabson svc_find(SVCPOOL *pool, rpcprog_t prog, rpcvers_t vers, char *netid)
292dfdcada3SDoug Rabson {
293dfdcada3SDoug Rabson 	struct svc_callout *s;
294dfdcada3SDoug Rabson 
295dfdcada3SDoug Rabson 	mtx_assert(&pool->sp_lock, MA_OWNED);
296dfdcada3SDoug Rabson 	TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
297dfdcada3SDoug Rabson 		if (s->sc_prog == prog && s->sc_vers == vers
298dfdcada3SDoug Rabson 		    && (netid == NULL || s->sc_netid == NULL ||
299dfdcada3SDoug Rabson 			strcmp(netid, s->sc_netid) == 0))
300dfdcada3SDoug Rabson 			break;
301dfdcada3SDoug Rabson 	}
302dfdcada3SDoug Rabson 
303dfdcada3SDoug Rabson 	return (s);
304dfdcada3SDoug Rabson }
305dfdcada3SDoug Rabson 
306dfdcada3SDoug Rabson /* ******************* REPLY GENERATION ROUTINES  ************ */
307dfdcada3SDoug Rabson 
308dfdcada3SDoug Rabson /*
309dfdcada3SDoug Rabson  * Send a reply to an rpc request
310dfdcada3SDoug Rabson  */
311dfdcada3SDoug Rabson bool_t
312dfdcada3SDoug Rabson svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, void * xdr_location)
313dfdcada3SDoug Rabson {
314dfdcada3SDoug Rabson 	struct rpc_msg rply;
315dfdcada3SDoug Rabson 
316dfdcada3SDoug Rabson 	rply.rm_direction = REPLY;
317dfdcada3SDoug Rabson 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
318dfdcada3SDoug Rabson 	rply.acpted_rply.ar_verf = xprt->xp_verf;
319dfdcada3SDoug Rabson 	rply.acpted_rply.ar_stat = SUCCESS;
320dfdcada3SDoug Rabson 	rply.acpted_rply.ar_results.where = xdr_location;
321dfdcada3SDoug Rabson 	rply.acpted_rply.ar_results.proc = xdr_results;
322dfdcada3SDoug Rabson 
323dfdcada3SDoug Rabson 	return (SVC_REPLY(xprt, &rply));
324dfdcada3SDoug Rabson }
325dfdcada3SDoug Rabson 
326dfdcada3SDoug Rabson /*
327dfdcada3SDoug Rabson  * No procedure error reply
328dfdcada3SDoug Rabson  */
329dfdcada3SDoug Rabson void
330dfdcada3SDoug Rabson svcerr_noproc(SVCXPRT *xprt)
331dfdcada3SDoug Rabson {
332dfdcada3SDoug Rabson 	struct rpc_msg rply;
333dfdcada3SDoug Rabson 
334dfdcada3SDoug Rabson 	rply.rm_direction = REPLY;
335dfdcada3SDoug Rabson 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
336dfdcada3SDoug Rabson 	rply.acpted_rply.ar_verf = xprt->xp_verf;
337dfdcada3SDoug Rabson 	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
338dfdcada3SDoug Rabson 
339dfdcada3SDoug Rabson 	SVC_REPLY(xprt, &rply);
340dfdcada3SDoug Rabson }
341dfdcada3SDoug Rabson 
342dfdcada3SDoug Rabson /*
343dfdcada3SDoug Rabson  * Can't decode args error reply
344dfdcada3SDoug Rabson  */
345dfdcada3SDoug Rabson void
346dfdcada3SDoug Rabson svcerr_decode(SVCXPRT *xprt)
347dfdcada3SDoug Rabson {
348dfdcada3SDoug Rabson 	struct rpc_msg rply;
349dfdcada3SDoug Rabson 
350dfdcada3SDoug Rabson 	rply.rm_direction = REPLY;
351dfdcada3SDoug Rabson 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
352dfdcada3SDoug Rabson 	rply.acpted_rply.ar_verf = xprt->xp_verf;
353dfdcada3SDoug Rabson 	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
354dfdcada3SDoug Rabson 
355dfdcada3SDoug Rabson 	SVC_REPLY(xprt, &rply);
356dfdcada3SDoug Rabson }
357dfdcada3SDoug Rabson 
358dfdcada3SDoug Rabson /*
359dfdcada3SDoug Rabson  * Some system error
360dfdcada3SDoug Rabson  */
361dfdcada3SDoug Rabson void
362dfdcada3SDoug Rabson svcerr_systemerr(SVCXPRT *xprt)
363dfdcada3SDoug Rabson {
364dfdcada3SDoug Rabson 	struct rpc_msg rply;
365dfdcada3SDoug Rabson 
366dfdcada3SDoug Rabson 	rply.rm_direction = REPLY;
367dfdcada3SDoug Rabson 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
368dfdcada3SDoug Rabson 	rply.acpted_rply.ar_verf = xprt->xp_verf;
369dfdcada3SDoug Rabson 	rply.acpted_rply.ar_stat = SYSTEM_ERR;
370dfdcada3SDoug Rabson 
371dfdcada3SDoug Rabson 	SVC_REPLY(xprt, &rply);
372dfdcada3SDoug Rabson }
373dfdcada3SDoug Rabson 
374dfdcada3SDoug Rabson /*
375dfdcada3SDoug Rabson  * Authentication error reply
376dfdcada3SDoug Rabson  */
377dfdcada3SDoug Rabson void
378dfdcada3SDoug Rabson svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
379dfdcada3SDoug Rabson {
380dfdcada3SDoug Rabson 	struct rpc_msg rply;
381dfdcada3SDoug Rabson 
382dfdcada3SDoug Rabson 	rply.rm_direction = REPLY;
383dfdcada3SDoug Rabson 	rply.rm_reply.rp_stat = MSG_DENIED;
384dfdcada3SDoug Rabson 	rply.rjcted_rply.rj_stat = AUTH_ERROR;
385dfdcada3SDoug Rabson 	rply.rjcted_rply.rj_why = why;
386dfdcada3SDoug Rabson 
387dfdcada3SDoug Rabson 	SVC_REPLY(xprt, &rply);
388dfdcada3SDoug Rabson }
389dfdcada3SDoug Rabson 
390dfdcada3SDoug Rabson /*
391dfdcada3SDoug Rabson  * Auth too weak error reply
392dfdcada3SDoug Rabson  */
393dfdcada3SDoug Rabson void
394dfdcada3SDoug Rabson svcerr_weakauth(SVCXPRT *xprt)
395dfdcada3SDoug Rabson {
396dfdcada3SDoug Rabson 
397dfdcada3SDoug Rabson 	svcerr_auth(xprt, AUTH_TOOWEAK);
398dfdcada3SDoug Rabson }
399dfdcada3SDoug Rabson 
400dfdcada3SDoug Rabson /*
401dfdcada3SDoug Rabson  * Program unavailable error reply
402dfdcada3SDoug Rabson  */
403dfdcada3SDoug Rabson void
404dfdcada3SDoug Rabson svcerr_noprog(SVCXPRT *xprt)
405dfdcada3SDoug Rabson {
406dfdcada3SDoug Rabson 	struct rpc_msg rply;
407dfdcada3SDoug Rabson 
408dfdcada3SDoug Rabson 	rply.rm_direction = REPLY;
409dfdcada3SDoug Rabson 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
410dfdcada3SDoug Rabson 	rply.acpted_rply.ar_verf = xprt->xp_verf;
411dfdcada3SDoug Rabson 	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
412dfdcada3SDoug Rabson 
413dfdcada3SDoug Rabson 	SVC_REPLY(xprt, &rply);
414dfdcada3SDoug Rabson }
415dfdcada3SDoug Rabson 
416dfdcada3SDoug Rabson /*
417dfdcada3SDoug Rabson  * Program version mismatch error reply
418dfdcada3SDoug Rabson  */
419dfdcada3SDoug Rabson void
420dfdcada3SDoug Rabson svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
421dfdcada3SDoug Rabson {
422dfdcada3SDoug Rabson 	struct rpc_msg rply;
423dfdcada3SDoug Rabson 
424dfdcada3SDoug Rabson 	rply.rm_direction = REPLY;
425dfdcada3SDoug Rabson 	rply.rm_reply.rp_stat = MSG_ACCEPTED;
426dfdcada3SDoug Rabson 	rply.acpted_rply.ar_verf = xprt->xp_verf;
427dfdcada3SDoug Rabson 	rply.acpted_rply.ar_stat = PROG_MISMATCH;
428dfdcada3SDoug Rabson 	rply.acpted_rply.ar_vers.low = (uint32_t)low_vers;
429dfdcada3SDoug Rabson 	rply.acpted_rply.ar_vers.high = (uint32_t)high_vers;
430dfdcada3SDoug Rabson 
431dfdcada3SDoug Rabson 	SVC_REPLY(xprt, &rply);
432dfdcada3SDoug Rabson }
433dfdcada3SDoug Rabson 
434dfdcada3SDoug Rabson /* ******************* SERVER INPUT STUFF ******************* */
435dfdcada3SDoug Rabson 
436dfdcada3SDoug Rabson /*
437dfdcada3SDoug Rabson  * Get server side input from some transport.
438dfdcada3SDoug Rabson  *
439dfdcada3SDoug Rabson  * Statement of authentication parameters management:
440dfdcada3SDoug Rabson  * This function owns and manages all authentication parameters, specifically
441dfdcada3SDoug Rabson  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
442dfdcada3SDoug Rabson  * the "cooked" credentials (rqst->rq_clntcred).
443dfdcada3SDoug Rabson  * In-kernel, we represent non-trivial cooked creds with struct ucred.
444dfdcada3SDoug Rabson  * In all events, all three parameters are freed upon exit from this routine.
445dfdcada3SDoug Rabson  * The storage is trivially management on the call stack in user land, but
446dfdcada3SDoug Rabson  * is mallocated in kernel land.
447dfdcada3SDoug Rabson  */
448dfdcada3SDoug Rabson 
449dfdcada3SDoug Rabson static void
450dfdcada3SDoug Rabson svc_getreq(SVCXPRT *xprt)
451dfdcada3SDoug Rabson {
452dfdcada3SDoug Rabson 	SVCPOOL *pool = xprt->xp_pool;
453dfdcada3SDoug Rabson 	struct svc_req r;
454dfdcada3SDoug Rabson 	struct rpc_msg msg;
455dfdcada3SDoug Rabson 	int prog_found;
456dfdcada3SDoug Rabson 	rpcvers_t low_vers;
457dfdcada3SDoug Rabson 	rpcvers_t high_vers;
458dfdcada3SDoug Rabson 	enum xprt_stat stat;
459dfdcada3SDoug Rabson 	char cred_area[2*MAX_AUTH_BYTES + sizeof(struct xucred)];
460dfdcada3SDoug Rabson 
461dfdcada3SDoug Rabson 	msg.rm_call.cb_cred.oa_base = cred_area;
462dfdcada3SDoug Rabson 	msg.rm_call.cb_verf.oa_base = &cred_area[MAX_AUTH_BYTES];
463dfdcada3SDoug Rabson 	r.rq_clntcred = &cred_area[2*MAX_AUTH_BYTES];
464dfdcada3SDoug Rabson 
465dfdcada3SDoug Rabson 	/* now receive msgs from xprtprt (support batch calls) */
466dfdcada3SDoug Rabson 	do {
467dfdcada3SDoug Rabson 		if (SVC_RECV(xprt, &msg)) {
468dfdcada3SDoug Rabson 
469dfdcada3SDoug Rabson 			/* now find the exported program and call it */
470dfdcada3SDoug Rabson 			struct svc_callout *s;
471dfdcada3SDoug Rabson 			enum auth_stat why;
472dfdcada3SDoug Rabson 
473dfdcada3SDoug Rabson 			r.rq_xprt = xprt;
474dfdcada3SDoug Rabson 			r.rq_prog = msg.rm_call.cb_prog;
475dfdcada3SDoug Rabson 			r.rq_vers = msg.rm_call.cb_vers;
476dfdcada3SDoug Rabson 			r.rq_proc = msg.rm_call.cb_proc;
477dfdcada3SDoug Rabson 			r.rq_cred = msg.rm_call.cb_cred;
478dfdcada3SDoug Rabson 			/* first authenticate the message */
479dfdcada3SDoug Rabson 			if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
480dfdcada3SDoug Rabson 				svcerr_auth(xprt, why);
481dfdcada3SDoug Rabson 				goto call_done;
482dfdcada3SDoug Rabson 			}
483dfdcada3SDoug Rabson 			/* now match message with a registered service*/
484dfdcada3SDoug Rabson 			prog_found = FALSE;
485dfdcada3SDoug Rabson 			low_vers = (rpcvers_t) -1L;
486dfdcada3SDoug Rabson 			high_vers = (rpcvers_t) 0L;
487dfdcada3SDoug Rabson 			TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
488dfdcada3SDoug Rabson 				if (s->sc_prog == r.rq_prog) {
489dfdcada3SDoug Rabson 					if (s->sc_vers == r.rq_vers) {
490dfdcada3SDoug Rabson 						(*s->sc_dispatch)(&r, xprt);
491dfdcada3SDoug Rabson 						goto call_done;
492dfdcada3SDoug Rabson 					}  /* found correct version */
493dfdcada3SDoug Rabson 					prog_found = TRUE;
494dfdcada3SDoug Rabson 					if (s->sc_vers < low_vers)
495dfdcada3SDoug Rabson 						low_vers = s->sc_vers;
496dfdcada3SDoug Rabson 					if (s->sc_vers > high_vers)
497dfdcada3SDoug Rabson 						high_vers = s->sc_vers;
498dfdcada3SDoug Rabson 				}   /* found correct program */
499dfdcada3SDoug Rabson 			}
500dfdcada3SDoug Rabson 			/*
501dfdcada3SDoug Rabson 			 * if we got here, the program or version
502dfdcada3SDoug Rabson 			 * is not served ...
503dfdcada3SDoug Rabson 			 */
504dfdcada3SDoug Rabson 			if (prog_found)
505dfdcada3SDoug Rabson 				svcerr_progvers(xprt, low_vers, high_vers);
506dfdcada3SDoug Rabson 			else
507dfdcada3SDoug Rabson 				svcerr_noprog(xprt);
508dfdcada3SDoug Rabson 			/* Fall through to ... */
509dfdcada3SDoug Rabson 		}
510dfdcada3SDoug Rabson 		/*
511dfdcada3SDoug Rabson 		 * Check if the xprt has been disconnected in a
512dfdcada3SDoug Rabson 		 * recursive call in the service dispatch routine.
513dfdcada3SDoug Rabson 		 * If so, then break.
514dfdcada3SDoug Rabson 		 */
515dfdcada3SDoug Rabson 		mtx_lock(&pool->sp_lock);
516dfdcada3SDoug Rabson 		if (!xprt->xp_registered) {
517dfdcada3SDoug Rabson 			mtx_unlock(&pool->sp_lock);
518dfdcada3SDoug Rabson 			break;
519dfdcada3SDoug Rabson 		}
520dfdcada3SDoug Rabson 		mtx_unlock(&pool->sp_lock);
521dfdcada3SDoug Rabson call_done:
522dfdcada3SDoug Rabson 		if ((stat = SVC_STAT(xprt)) == XPRT_DIED) {
523dfdcada3SDoug Rabson 			SVC_DESTROY(xprt);
524dfdcada3SDoug Rabson 			break;
525dfdcada3SDoug Rabson 		}
526dfdcada3SDoug Rabson 	} while (stat == XPRT_MOREREQS);
527dfdcada3SDoug Rabson }
528dfdcada3SDoug Rabson 
529dfdcada3SDoug Rabson void
530dfdcada3SDoug Rabson svc_run(SVCPOOL *pool)
531dfdcada3SDoug Rabson {
532dfdcada3SDoug Rabson 	SVCXPRT *xprt;
533dfdcada3SDoug Rabson 	int error;
534dfdcada3SDoug Rabson 
535dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
536dfdcada3SDoug Rabson 
537dfdcada3SDoug Rabson 	pool->sp_exited = FALSE;
538dfdcada3SDoug Rabson 
539dfdcada3SDoug Rabson 	while (!pool->sp_exited) {
540dfdcada3SDoug Rabson 		xprt = TAILQ_FIRST(&pool->sp_active);
541dfdcada3SDoug Rabson 		if (!xprt) {
542dfdcada3SDoug Rabson 			error = msleep(&pool->sp_active, &pool->sp_lock, PCATCH,
543dfdcada3SDoug Rabson 			    "rpcsvc", 0);
544dfdcada3SDoug Rabson 			if (error)
545dfdcada3SDoug Rabson 				break;
546dfdcada3SDoug Rabson 			continue;
547dfdcada3SDoug Rabson 		}
548dfdcada3SDoug Rabson 
549dfdcada3SDoug Rabson 		/*
550dfdcada3SDoug Rabson 		 * Move this transport to the end to ensure fairness
551dfdcada3SDoug Rabson 		 * when multiple transports are active. If this was
552dfdcada3SDoug Rabson 		 * the last queued request, svc_getreq will end up
553dfdcada3SDoug Rabson 		 * calling xprt_inactive to remove from the active
554dfdcada3SDoug Rabson 		 * list.
555dfdcada3SDoug Rabson 		 */
556dfdcada3SDoug Rabson 		TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
557dfdcada3SDoug Rabson 		TAILQ_INSERT_TAIL(&pool->sp_active, xprt, xp_alink);
558dfdcada3SDoug Rabson 
559dfdcada3SDoug Rabson 		mtx_unlock(&pool->sp_lock);
560dfdcada3SDoug Rabson 		svc_getreq(xprt);
561dfdcada3SDoug Rabson 		mtx_lock(&pool->sp_lock);
562dfdcada3SDoug Rabson 	}
563dfdcada3SDoug Rabson 
564dfdcada3SDoug Rabson 	mtx_unlock(&pool->sp_lock);
565dfdcada3SDoug Rabson }
566dfdcada3SDoug Rabson 
567dfdcada3SDoug Rabson void
568dfdcada3SDoug Rabson svc_exit(SVCPOOL *pool)
569dfdcada3SDoug Rabson {
570dfdcada3SDoug Rabson 	mtx_lock(&pool->sp_lock);
571dfdcada3SDoug Rabson 	pool->sp_exited = TRUE;
572dfdcada3SDoug Rabson 	wakeup(&pool->sp_active);
573dfdcada3SDoug Rabson 	mtx_unlock(&pool->sp_lock);
574dfdcada3SDoug Rabson }
575