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