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