1/*	$NetBSD: svc.c,v 1.3 2010/07/26 18:51:02 pooka Exp $	*/
2
3/*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part.  Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California  94043
30 */
31
32#include <sys/cdefs.h>
33#if defined(LIBC_SCCS) && !defined(lint)
34#if 0
35static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
36static char *sccsid = "@(#)svc.c	2.4 88/08/11 4.0 RPCSRC";
37#else
38__RCSID("$NetBSD: svc.c,v 1.3 2010/07/26 18:51:02 pooka Exp $");
39#endif
40#endif
41
42/*
43 * svc.c, Server-side remote procedure call interface.
44 *
45 * There are two sets of procedures here.  The xprt routines are
46 * for handling transport handles.  The svc routines handle the
47 * list of service routines.
48 *
49 * Copyright (C) 1984, Sun Microsystems, Inc.
50 */
51
52#include "namespace.h"
53#include "reentrant.h"
54#include <sys/types.h>
55#include <sys/poll.h>
56#include <assert.h>
57#include <errno.h>
58#include <stdlib.h>
59#include <string.h>
60#include <err.h>
61
62#include <rpc/rpc.h>
63#ifdef PORTMAP
64#include <rpc/pmap_clnt.h>
65#endif
66
67#include "rpc_internal.h"
68#include "svc_fdset.h"
69
70#ifdef __weak_alias
71__weak_alias(svc_getreq,_svc_getreq)
72__weak_alias(svc_getreqset,_svc_getreqset)
73__weak_alias(svc_getreq_common,_svc_getreq_common)
74__weak_alias(svc_register,_svc_register)
75__weak_alias(svc_reg,_svc_reg)
76__weak_alias(svc_unreg,_svc_unreg)
77__weak_alias(svc_sendreply,_svc_sendreply)
78__weak_alias(svc_unregister,_svc_unregister)
79__weak_alias(svcerr_auth,_svcerr_auth)
80__weak_alias(svcerr_decode,_svcerr_decode)
81__weak_alias(svcerr_noproc,_svcerr_noproc)
82__weak_alias(svcerr_noprog,_svcerr_noprog)
83__weak_alias(svcerr_progvers,_svcerr_progvers)
84__weak_alias(svcerr_systemerr,_svcerr_systemerr)
85__weak_alias(svcerr_weakauth,_svcerr_weakauth)
86__weak_alias(xprt_register,_xprt_register)
87__weak_alias(xprt_unregister,_xprt_unregister)
88__weak_alias(rpc_control,_rpc_control)
89#endif
90
91SVCXPRT **__svc_xports;
92int __svc_maxrec;
93
94#define	RQCRED_SIZE	400		/* this size is excessive */
95
96#define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
97#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
98
99#define max(a, b) (a > b ? a : b)
100
101/*
102 * The services list
103 * Each entry represents a set of procedures (an rpc program).
104 * The dispatch routine takes request structs and runs the
105 * apropriate procedure.
106 */
107static struct svc_callout {
108	struct svc_callout *sc_next;
109	rpcprog_t	    sc_prog;
110	rpcvers_t	    sc_vers;
111	char		   *sc_netid;
112	void		    (*sc_dispatch) __P((struct svc_req *, SVCXPRT *));
113} *svc_head;
114
115#ifdef _REENTRANT
116extern rwlock_t svc_lock;
117extern rwlock_t svc_fd_lock;
118#endif
119
120static struct svc_callout *svc_find __P((rpcprog_t, rpcvers_t,
121					 struct svc_callout **, char *));
122static void __xprt_do_unregister __P((SVCXPRT *xprt, bool_t dolock));
123
124#include <pthread.h>
125
126static pthread_key_t fdsetkey;
127static pthread_key_t fdmaxkey;
128static fd_set thefdset;
129static int thefdmax;
130
131void
132init_fdsets()
133{
134
135	pthread_key_create(&fdsetkey, NULL);
136	pthread_key_create(&fdmaxkey, NULL);
137}
138
139void
140alloc_fdset()
141{
142	fd_set *fdsetti;
143	int *fdmax;
144
145	fdsetti = malloc(sizeof(*fdsetti));
146	memset(fdsetti, 0, sizeof(*fdsetti));
147	pthread_setspecific(fdsetkey, fdsetti);
148
149	fdmax = malloc(sizeof(*fdmax));
150	memset(fdmax, 0, sizeof(*fdmax));
151	pthread_setspecific(fdmaxkey, fdmax);
152}
153
154fd_set *
155get_fdset()
156{
157	fd_set *rv;
158
159	rv = pthread_getspecific(fdsetkey);
160	if (rv)
161		return rv;
162	else
163		return &thefdset;
164}
165
166int *
167get_fdsetmax()
168{
169	int *rv;
170
171	rv = pthread_getspecific(fdmaxkey);
172	if (rv)
173		return rv;
174	else
175		return &thefdmax;
176}
177
178/* ***************  SVCXPRT related stuff **************** */
179
180/*
181 * Activate a transport handle.
182 */
183void
184xprt_register(xprt)
185	SVCXPRT *xprt;
186{
187	int sock;
188
189	_DIAGASSERT(xprt != NULL);
190
191	sock = xprt->xp_fd;
192
193	rwlock_wrlock(&svc_fd_lock);
194	if (__svc_xports == NULL) {
195		__svc_xports = mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
196		if (__svc_xports == NULL) {
197			warn("xprt_register");
198			goto out;
199		}
200		memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
201	}
202	if (sock < FD_SETSIZE) {
203		__svc_xports[sock] = xprt;
204		FD_SET(sock, get_fdset());
205		*get_fdsetmax() = max(*get_fdsetmax(), sock);
206	}
207out:
208	rwlock_unlock(&svc_fd_lock);
209}
210
211void
212xprt_unregister(SVCXPRT *xprt)
213{
214	__xprt_do_unregister(xprt, TRUE);
215}
216
217void
218__xprt_unregister_unlocked(SVCXPRT *xprt)
219{
220	__xprt_do_unregister(xprt, FALSE);
221}
222
223/*
224 * De-activate a transport handle.
225 */
226static void
227__xprt_do_unregister(xprt, dolock)
228	SVCXPRT *xprt;
229	bool_t dolock;
230{
231	int sock;
232
233	_DIAGASSERT(xprt != NULL);
234
235	sock = xprt->xp_fd;
236
237	if (dolock)
238		rwlock_wrlock(&svc_fd_lock);
239	if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
240		__svc_xports[sock] = NULL;
241		FD_CLR(sock, get_fdset());
242		if (sock >= *get_fdsetmax()) {
243			for ((*get_fdsetmax())--; *get_fdsetmax()>=0; (*get_fdsetmax())--)
244				if (__svc_xports[*get_fdsetmax()])
245					break;
246		}
247	}
248	if (dolock)
249		rwlock_unlock(&svc_fd_lock);
250}
251
252#include <stdio.h>
253
254/*
255 * Add a service program to the callout list.
256 * The dispatch routine will be called when a rpc request for this
257 * program number comes in.
258 */
259bool_t
260svc_reg(xprt, prog, vers, dispatch, nconf)
261	SVCXPRT *xprt;
262	const rpcprog_t prog;
263	const rpcvers_t vers;
264	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
265	const struct netconfig *nconf;
266{
267	bool_t dummy;
268	struct svc_callout *prev;
269	struct svc_callout *s;
270	struct netconfig *tnconf;
271	char *netid = NULL;
272	int flag = 0;
273
274	_DIAGASSERT(xprt != NULL);
275	/* XXX: dispatch may be NULL ??? */
276
277/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
278
279	if (xprt->xp_netid) {
280		netid = strdup(xprt->xp_netid);
281		flag = 1;
282	} else if (nconf && nconf->nc_netid) {
283		netid = strdup(nconf->nc_netid);
284		flag = 1;
285	} else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
286		netid = strdup(tnconf->nc_netid);
287		flag = 1;
288		freenetconfigent(tnconf);
289	} /* must have been created with svc_raw_create */
290	if ((netid == NULL) && (flag == 1)) {
291		return (FALSE);
292	}
293
294	rwlock_wrlock(&svc_lock);
295	if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
296		if (netid)
297			free(netid);
298		if (s->sc_dispatch == dispatch)
299			goto rpcb_it; /* he is registering another xptr */
300		rwlock_unlock(&svc_lock);
301		return (FALSE);
302	}
303	s = mem_alloc(sizeof (struct svc_callout));
304	if (s == NULL) {
305		if (netid)
306			free(netid);
307		rwlock_unlock(&svc_lock);
308		return (FALSE);
309	}
310
311	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
312		if ((((SVCXPRT *) xprt)->xp_netid = strdup(netid)) == NULL) {
313			warn("svc_reg");
314			mem_free(s, sizeof(struct svc_callout));
315			rwlock_unlock(&svc_lock);
316			return FALSE;
317		}
318
319	s->sc_prog = prog;
320	s->sc_vers = vers;
321	s->sc_dispatch = dispatch;
322	s->sc_netid = netid;
323	s->sc_next = svc_head;
324	svc_head = s;
325
326rpcb_it:
327	rwlock_unlock(&svc_lock);
328	/* now register the information with the local binder service */
329	if (nconf) {
330		dummy = rpcb_set(prog, vers, __UNCONST(nconf),
331		&((SVCXPRT *) xprt)->xp_ltaddr);
332		return (dummy);
333	}
334	return (TRUE);
335}
336
337/*
338 * Remove a service program from the callout list.
339 */
340void
341svc_unreg(prog, vers)
342	const rpcprog_t prog;
343	const rpcvers_t vers;
344{
345	struct svc_callout *prev;
346	struct svc_callout *s;
347
348	/* unregister the information anyway */
349	(void) rpcb_unset(prog, vers, NULL);
350	rwlock_wrlock(&svc_lock);
351	while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
352		if (prev == NULL) {
353			svc_head = s->sc_next;
354		} else {
355			prev->sc_next = s->sc_next;
356		}
357		s->sc_next = NULL;
358		if (s->sc_netid)
359			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
360		mem_free(s, sizeof (struct svc_callout));
361	}
362	rwlock_unlock(&svc_lock);
363}
364
365/* ********************** CALLOUT list related stuff ************* */
366
367#ifdef PORTMAP
368/*
369 * Add a service program to the callout list.
370 * The dispatch routine will be called when a rpc request for this
371 * program number comes in.
372 */
373bool_t
374svc_register(xprt, prog, vers, dispatch, protocol)
375	SVCXPRT *xprt;
376	u_long prog;
377	u_long vers;
378	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
379	int protocol;
380{
381	struct svc_callout *prev;
382	struct svc_callout *s;
383
384	_DIAGASSERT(xprt != NULL);
385	_DIAGASSERT(dispatch != NULL);
386
387	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
388	    NULL) {
389		if (s->sc_dispatch == dispatch)
390			goto pmap_it;  /* he is registering another xptr */
391		return (FALSE);
392	}
393	s = mem_alloc(sizeof(struct svc_callout));
394	if (s == NULL) {
395		return (FALSE);
396	}
397	s->sc_prog = (rpcprog_t)prog;
398	s->sc_vers = (rpcvers_t)vers;
399	s->sc_dispatch = dispatch;
400	s->sc_next = svc_head;
401	svc_head = s;
402pmap_it:
403	/* now register the information with the local binder service */
404	if (protocol) {
405		return (pmap_set(prog, vers, protocol, xprt->xp_port));
406	}
407	return (TRUE);
408}
409
410/*
411 * Remove a service program from the callout list.
412 */
413void
414svc_unregister(prog, vers)
415	u_long prog;
416	u_long vers;
417{
418	struct svc_callout *prev;
419	struct svc_callout *s;
420
421	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
422	    NULL)
423		return;
424	if (prev == NULL) {
425		svc_head = s->sc_next;
426	} else {
427		prev->sc_next = s->sc_next;
428	}
429	s->sc_next = NULL;
430	mem_free(s, sizeof(struct svc_callout));
431	/* now unregister the information with the local binder service */
432	(void)pmap_unset(prog, vers);
433}
434#endif /* PORTMAP */
435
436/*
437 * Search the callout list for a program number, return the callout
438 * struct.
439 */
440static struct svc_callout *
441svc_find(prog, vers, prev, netid)
442	rpcprog_t prog;
443	rpcvers_t vers;
444	struct svc_callout **prev;
445	char *netid;
446{
447	struct svc_callout *s, *p;
448
449	_DIAGASSERT(prev != NULL);
450	/* netid is handled below */
451
452	p = NULL;
453	for (s = svc_head; s != NULL; s = s->sc_next) {
454		if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
455		    ((netid == NULL) || (s->sc_netid == NULL) ||
456		    (strcmp(netid, s->sc_netid) == 0)))
457			break;
458		p = s;
459	}
460	*prev = p;
461	return (s);
462}
463
464/* ******************* REPLY GENERATION ROUTINES  ************ */
465
466/*
467 * Send a reply to an rpc request
468 */
469bool_t
470svc_sendreply(xprt, xdr_results, xdr_location)
471	SVCXPRT *xprt;
472	xdrproc_t xdr_results;
473	const char *xdr_location;
474{
475	struct rpc_msg rply;
476
477	_DIAGASSERT(xprt != NULL);
478
479	rply.rm_direction = REPLY;
480	rply.rm_reply.rp_stat = MSG_ACCEPTED;
481	rply.acpted_rply.ar_verf = xprt->xp_verf;
482	rply.acpted_rply.ar_stat = SUCCESS;
483	rply.acpted_rply.ar_results.where = xdr_location;
484	rply.acpted_rply.ar_results.proc = xdr_results;
485	return (SVC_REPLY(xprt, &rply));
486}
487
488/*
489 * No procedure error reply
490 */
491void
492svcerr_noproc(xprt)
493	SVCXPRT *xprt;
494{
495	struct rpc_msg rply;
496
497	_DIAGASSERT(xprt != NULL);
498
499	rply.rm_direction = REPLY;
500	rply.rm_reply.rp_stat = MSG_ACCEPTED;
501	rply.acpted_rply.ar_verf = xprt->xp_verf;
502	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
503	SVC_REPLY(xprt, &rply);
504}
505
506/*
507 * Can't decode args error reply
508 */
509void
510svcerr_decode(xprt)
511	SVCXPRT *xprt;
512{
513	struct rpc_msg rply;
514
515	_DIAGASSERT(xprt != NULL);
516
517	rply.rm_direction = REPLY;
518	rply.rm_reply.rp_stat = MSG_ACCEPTED;
519	rply.acpted_rply.ar_verf = xprt->xp_verf;
520	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
521	SVC_REPLY(xprt, &rply);
522}
523
524/*
525 * Some system error
526 */
527void
528svcerr_systemerr(xprt)
529	SVCXPRT *xprt;
530{
531	struct rpc_msg rply;
532
533	_DIAGASSERT(xprt != NULL);
534
535	rply.rm_direction = REPLY;
536	rply.rm_reply.rp_stat = MSG_ACCEPTED;
537	rply.acpted_rply.ar_verf = xprt->xp_verf;
538	rply.acpted_rply.ar_stat = SYSTEM_ERR;
539	SVC_REPLY(xprt, &rply);
540}
541
542#if 0
543/*
544 * Tell RPC package to not complain about version errors to the client.	 This
545 * is useful when revving broadcast protocols that sit on a fixed address.
546 * There is really one (or should be only one) example of this kind of
547 * protocol: the portmapper (or rpc binder).
548 */
549void
550__svc_versquiet_on(xprt)
551	SVCXPRT *xprt;
552{
553	u_long	tmp;
554
555	_DIAGASSERT(xprt != NULL);
556
557	tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
558	xprt->xp_p3 = (caddr_t) tmp;
559}
560
561void
562__svc_versquiet_off(xprt)
563	SVCXPRT *xprt;
564{
565	u_long	tmp;
566
567	_DIAGASSERT(xprt != NULL);
568
569	tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
570	xprt->xp_p3 = (caddr_t) tmp;
571}
572
573void
574svc_versquiet(xprt)
575	SVCXPRT *xprt;
576{
577	__svc_versquiet_on(xprt);
578}
579
580int
581__svc_versquiet_get(xprt)
582	SVCXPRT *xprt;
583{
584
585	_DIAGASSERT(xprt != NULL);
586
587	return ((int) xprt->xp_p3) & SVC_VERSQUIET;
588}
589#endif
590
591/*
592 * Authentication error reply
593 */
594void
595svcerr_auth(xprt, why)
596	SVCXPRT *xprt;
597	enum auth_stat why;
598{
599	struct rpc_msg rply;
600
601	_DIAGASSERT(xprt != NULL);
602
603	rply.rm_direction = REPLY;
604	rply.rm_reply.rp_stat = MSG_DENIED;
605	rply.rjcted_rply.rj_stat = AUTH_ERROR;
606	rply.rjcted_rply.rj_why = why;
607	SVC_REPLY(xprt, &rply);
608}
609
610/*
611 * Auth too weak error reply
612 */
613void
614svcerr_weakauth(xprt)
615	SVCXPRT *xprt;
616{
617
618	_DIAGASSERT(xprt != NULL);
619
620	svcerr_auth(xprt, AUTH_TOOWEAK);
621}
622
623/*
624 * Program unavailable error reply
625 */
626void
627svcerr_noprog(xprt)
628	SVCXPRT *xprt;
629{
630	struct rpc_msg rply;
631
632	_DIAGASSERT(xprt != NULL);
633
634	rply.rm_direction = REPLY;
635	rply.rm_reply.rp_stat = MSG_ACCEPTED;
636	rply.acpted_rply.ar_verf = xprt->xp_verf;
637	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
638	SVC_REPLY(xprt, &rply);
639}
640
641/*
642 * Program version mismatch error reply
643 */
644void
645svcerr_progvers(xprt, low_vers, high_vers)
646	SVCXPRT *xprt;
647	rpcvers_t low_vers;
648	rpcvers_t high_vers;
649{
650	struct rpc_msg rply;
651
652	_DIAGASSERT(xprt != NULL);
653
654	rply.rm_direction = REPLY;
655	rply.rm_reply.rp_stat = MSG_ACCEPTED;
656	rply.acpted_rply.ar_verf = xprt->xp_verf;
657	rply.acpted_rply.ar_stat = PROG_MISMATCH;
658	rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
659	rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
660	SVC_REPLY(xprt, &rply);
661}
662
663/* ******************* SERVER INPUT STUFF ******************* */
664
665/*
666 * Get server side input from some transport.
667 *
668 * Statement of authentication parameters management:
669 * This function owns and manages all authentication parameters, specifically
670 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
671 * the "cooked" credentials (rqst->rq_clntcred).
672 * However, this function does not know the structure of the cooked
673 * credentials, so it make the following assumptions:
674 *   a) the structure is contiguous (no pointers), and
675 *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
676 * In all events, all three parameters are freed upon exit from this routine.
677 * The storage is trivially management on the call stack in user land, but
678 * is mallocated in kernel land.
679 */
680
681void
682svc_getreq(rdfds)
683	int rdfds;
684{
685	fd_set readfds;
686
687	FD_ZERO(&readfds);
688	readfds.fds_bits[0] = rdfds;
689	svc_getreqset(&readfds);
690}
691
692void
693svc_getreqset(readfds)
694	fd_set *readfds;
695{
696	int bit, fd;
697	uint32_t mask, *maskp;
698	int sock;
699
700	_DIAGASSERT(readfds != NULL);
701
702	maskp = (uint32_t *)readfds->fds_bits;
703	for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
704	    for (mask = *maskp++; (bit = ffs(mask)) != 0;
705		mask ^= (1 << (bit - 1))) {
706		/* sock has input waiting */
707		fd = sock + bit - 1;
708		svc_getreq_common(fd);
709	    }
710	}
711}
712
713void
714svc_getreq_common(fd)
715	int fd;
716{
717	SVCXPRT *xprt;
718	struct svc_req r;
719	struct rpc_msg msg;
720	int prog_found;
721	rpcvers_t low_vers;
722	rpcvers_t high_vers;
723	enum xprt_stat stat;
724	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
725
726	msg.rm_call.cb_cred.oa_base = cred_area;
727	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
728	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
729
730	rwlock_rdlock(&svc_fd_lock);
731	xprt = __svc_xports[fd];
732	rwlock_unlock(&svc_fd_lock);
733	if (xprt == NULL)
734		/* But do we control sock? */
735		return;
736	/* now receive msgs from xprtprt (support batch calls) */
737	do {
738		if (SVC_RECV(xprt, &msg)) {
739
740			/* now find the exported program and call it */
741			struct svc_callout *s;
742			enum auth_stat why;
743
744			r.rq_xprt = xprt;
745			r.rq_prog = msg.rm_call.cb_prog;
746			r.rq_vers = msg.rm_call.cb_vers;
747			r.rq_proc = msg.rm_call.cb_proc;
748			r.rq_cred = msg.rm_call.cb_cred;
749			/* first authenticate the message */
750			if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
751				svcerr_auth(xprt, why);
752				goto call_done;
753			}
754			/* now match message with a registered service*/
755			prog_found = FALSE;
756			low_vers = (rpcvers_t) -1L;
757			high_vers = (rpcvers_t) 0L;
758			for (s = svc_head; s != NULL; s = s->sc_next) {
759				if (s->sc_prog == r.rq_prog) {
760					if (s->sc_vers == r.rq_vers) {
761						(*s->sc_dispatch)(&r, xprt);
762						goto call_done;
763					}  /* found correct version */
764					prog_found = TRUE;
765					if (s->sc_vers < low_vers)
766						low_vers = s->sc_vers;
767					if (s->sc_vers > high_vers)
768						high_vers = s->sc_vers;
769				}   /* found correct program */
770			}
771			/*
772			 * if we got here, the program or version
773			 * is not served ...
774			 */
775			if (prog_found)
776				svcerr_progvers(xprt, low_vers, high_vers);
777			else
778				 svcerr_noprog(xprt);
779			/* Fall through to ... */
780		}
781call_done:
782		/*
783		 * Check if the xprt has been disconnected in a
784		 * recursive call in the service dispatch routine.
785		 * If so, then break.
786		 */
787		rwlock_rdlock(&svc_fd_lock);
788		if (xprt != __svc_xports[fd]) {
789			rwlock_unlock(&svc_fd_lock);
790			break;
791		}
792		rwlock_unlock(&svc_fd_lock);
793		if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
794			SVC_DESTROY(xprt);
795			break;
796		}
797	} while (stat == XPRT_MOREREQS);
798}
799
800
801void
802svc_getreq_poll(pfdp, pollretval)
803	struct pollfd	*pfdp;
804	int	pollretval;
805{
806	int i;
807	int fds_found;
808
809	_DIAGASSERT(pfdp != NULL);
810
811	for (i = fds_found = 0; fds_found < pollretval; i++) {
812		struct pollfd *p = &pfdp[i];
813
814		if (p->revents) {
815			/* fd has input waiting */
816			fds_found++;
817			/*
818			 *	We assume that this function is only called
819			 *	via someone select()ing from svc_fdset or
820			 *	pollts()ing from svc_pollset[].  Thus it's safe
821			 *	to handle the POLLNVAL event by simply turning
822			 *	the corresponding bit off in svc_fdset.  The
823			 *	svc_pollset[] array is derived from svc_fdset
824			 *	and so will also be updated eventually.
825			 *
826			 *	XXX Should we do an xprt_unregister() instead?
827			 */
828			if (p->revents & POLLNVAL) {
829				rwlock_wrlock(&svc_fd_lock);
830				FD_CLR(p->fd, get_fdset());
831				rwlock_unlock(&svc_fd_lock);
832			} else
833				svc_getreq_common(p->fd);
834		}
835	}
836}
837
838bool_t
839rpc_control(int what, void *arg)
840{
841	int val;
842
843	switch (what) {
844	case RPC_SVC_CONNMAXREC_SET:
845		val = *(int *)arg;
846		if (val <= 0)
847			return FALSE;
848		__svc_maxrec = val;
849		return TRUE;
850	case RPC_SVC_CONNMAXREC_GET:
851		*(int *)arg = __svc_maxrec;
852		return TRUE;
853	default:
854		break;
855	}
856	return FALSE;
857}
858