xref: /titanic_52/usr/src/cmd/avs/rdc/sndrd.c (revision a4aef2bab3a15f31b03de3834937be168fb83b36)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Network SNDR/ncall-ip server - based on nfsd
28  */
29 #include <sys/types.h>
30 #include <rpc/types.h>
31 #include <errno.h>
32 #include <netdb.h>
33 #include <sys/socket.h>
34 #include <netconfig.h>
35 #include <stropts.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <strings.h>
39 #include <signal.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <netdir.h>
43 #include <rpc/rpc_com.h>
44 #include <rpc/rpc.h>
45 #include <tiuser.h>
46 #include <netinet/tcp.h>
47 #include <netinet/in.h>
48 #include <syslog.h>
49 #include <locale.h>
50 #include <langinfo.h>
51 #include <libintl.h>
52 #include <libgen.h>
53 #include <deflt.h>
54 #include <sys/resource.h>
55 
56 #include <sys/nsctl/nsctl.h>
57 
58 #ifdef	__NCALL__
59 
60 #include <sys/ncall/ncall.h>
61 #include <sys/ncall/ncall_ip.h>
62 #include <sys/nsctl/libncall.h>
63 
64 #define	RDC_POOL_CREATE	NC_IOC_POOL_CREATE
65 #define	RDC_POOL_RUN	NC_IOC_POOL_RUN
66 #define	RDC_POOL_WAIT	NC_IOC_POOL_WAIT
67 #define	RDC_PROGRAM	NCALL_PROGRAM
68 #define	RDC_SERVICE	"ncall"
69 #undef RDC_SVCPOOL_ID	/* We are overloading this value */
70 #define	RDC_SVCPOOL_ID	NCALL_SVCPOOL_ID
71 #define	RDC_SVC_NAME	"NCALL"
72 #define	RDC_VERS_MIN	NCALL_VERS_MIN
73 #define	RDC_VERS_MAX	NCALL_VERS_MAX
74 
75 #else	/* !__NCALL__ */
76 
77 #include <sys/nsctl/rdc_ioctl.h>
78 #include <sys/nsctl/rdc_io.h>
79 #include <sys/nsctl/librdc.h>
80 
81 #define	RDC_SERVICE	"rdc"
82 #define	RDC_SVC_NAME	"RDC"
83 
84 #endif	/* __NCALL__ */
85 
86 #define	RDCADMIN	"/etc/default/sndr"
87 
88 #include <nsctl.h>
89 
90 struct conn_ind {
91 	struct conn_ind *conn_next;
92 	struct conn_ind *conn_prev;
93 	struct t_call   *conn_call;
94 };
95 
96 struct conn_entry {
97 	bool_t			closing;
98 	struct netconfig	nc;
99 };
100 
101 static char *progname;
102 static struct conn_entry *conn_polled;
103 static int num_conns;			/* Current number of connections */
104 static struct pollfd *poll_array;	/* array of poll descriptors for poll */
105 static size_t num_fds = 0;		/* number of transport fds opened */
106 static void poll_for_action();
107 static void remove_from_poll_list(int);
108 static int do_poll_cots_action(int, int);
109 static int do_poll_clts_action(int, int);
110 static void add_to_poll_list(int, struct netconfig *);
111 static int bind_to_provider(char *, char *, struct netbuf **,
112     struct netconfig **);
113 static int set_addrmask(int, struct netconfig *, struct netbuf *);
114 static void conn_close_oldest(void);
115 static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
116 static void cots_listen_event(int, int);
117 static int discon_get(int, struct netconfig *, struct conn_ind **);
118 static int nofile_increase(int);
119 static int is_listen_fd_index(int);
120 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
121 static int sndrsvcpool(int);
122 static int svcwait(int id);
123 #endif
124 
125 
126 /*
127  * RPC protocol block.  Useful for passing registration information.
128  */
129 struct protob {
130 	char *serv;		/* ASCII service name, e.g. "RDC" */
131 	int versmin;		/* minimum version no. to be registered */
132 	int versmax;		/* maximum version no. to be registered */
133 	int program;		/* program no. to be registered */
134 	struct protob *next;	/* next entry on list */
135 };
136 
137 
138 
139 static size_t end_listen_fds;
140 static int debugflg = 0;
141 static int max_conns_allowed = -1;
142 static int listen_backlog = 10;
143 static char *trans_provider = (char *)NULL;
144 static int rdcsvc(int, struct netbuf, struct netconfig *);
145 
146 /* used by cots_listen_event() */
147 static int (*Mysvc)(int, struct netbuf, struct netconfig *) = rdcsvc;
148 
149 /*
150  * Determine valid semantics for rdc.
151  */
152 #define	OK_TPI_TYPE(_nconf)	\
153 	(_nconf->nc_semantics == NC_TPI_CLTS || \
154 	_nconf->nc_semantics == NC_TPI_COTS || \
155 	_nconf->nc_semantics == NC_TPI_COTS_ORD)
156 
157 #define	BE32_TO_U32(a)		\
158 	((((uint32_t)((uchar_t *)a)[0] & 0xFF) << (uint32_t)24) |\
159 	(((uint32_t)((uchar_t *)a)[1] & 0xFF) << (uint32_t)16) |\
160 	(((uint32_t)((uchar_t *)a)[2] & 0xFF) << (uint32_t)8)  |\
161 	((uint32_t)((uchar_t *)a)[3] & 0xFF))
162 
163 #ifdef DEBUG
164 /*
165  * Only support UDP in DEBUG mode for now
166  */
167 static	char *defaultproviders[] = { "/dev/tcp", "/dev/tcp6", "/dev/udp",
168 		"/dev/udp6", NULL };
169 #else
170 static	char *defaultproviders[] = { "/dev/tcp6", "/dev/tcp", NULL };
171 #endif
172 
173 /*
174  * Number of elements to add to the poll array on each allocation.
175  */
176 #define	POLL_ARRAY_INC_SIZE	64
177 #define	NOFILE_INC_SIZE		64
178 
179 #ifdef	__NCALL__
180 const char *rdc_devr = "/dev/ncallip";
181 #else
182 const char *rdc_devr = "/dev/rdc";
183 #endif
184 
185 static int rdc_fdr;
186 static int
187 
188 open_rdc(void)
189 {
190 	int fd = open(rdc_devr, O_RDONLY);
191 
192 	if (fd < 0)
193 		return (-1);
194 
195 	return (rdc_fdr = fd);
196 }
197 
198 static int
199 sndrsys(int type, void *arg)
200 {
201 	int ret = -1;
202 	if (!rdc_fdr && open_rdc() < 0) { /* open failed */
203 		syslog(LOG_ERR, "open_rdc() failed: %m\n");
204 	} else {
205 		if ((ret = ioctl(rdc_fdr, type, arg)) < 0) {
206 			syslog(LOG_ERR, "ioctl(rdc_ioctl) failed: %m\n");
207 		}
208 	}
209 	return (ret);
210 }
211 
212 int
213 rdc_transport_open(struct netconfig *nconf)
214 {
215 	int fd;
216 	struct strioctl	strioc;
217 
218 	if ((nconf == (struct netconfig *)NULL) ||
219 	    (nconf->nc_device == (char *)NULL)) {
220 		syslog(LOG_ERR, "No netconfig device");
221 		return (-1);
222 	}
223 
224 	/*
225 	 * Open the transport device.
226 	 */
227 	fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
228 	if (fd == -1)  {
229 		if (t_errno == TSYSERR && errno == EMFILE &&
230 				(nofile_increase(0) == 0)) {
231 			/* Try again with a higher NOFILE limit. */
232 			fd = t_open(nconf->nc_device, O_RDWR,
233 				(struct t_info *)NULL);
234 		}
235 		if (fd == -1) {
236 			if (t_errno == TSYSERR) {
237 				syslog(LOG_ERR, "t_open failed: %m");
238 			} else {
239 				syslog(LOG_ERR, "t_open failed: %s",
240 				    t_errlist[t_errno]);
241 			}
242 			return (-1);
243 		}
244 	}
245 
246 	/*
247 	 * Pop timod because the RPC module must be as close as possible
248 	 * to the transport.
249 	 */
250 	if (ioctl(fd, I_POP, 0) < 0) {
251 		syslog(LOG_ERR, "I_POP of timod failed: %m");
252 		if (t_close(fd) == -1) {
253 			if (t_errno == TSYSERR) {
254 				syslog(LOG_ERR, "t_close failed on %d: %m", fd);
255 			} else {
256 				syslog(LOG_ERR, "t_close failed on %d: %s",
257 				    fd, t_errlist[t_errno]);
258 			}
259 		}
260 		return (-1);
261 	}
262 
263 	if (nconf->nc_semantics == NC_TPI_CLTS) {
264 		/*
265 		 * Push rpcmod to filter data traffic to KRPC.
266 		 */
267 		if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
268 			syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
269 			(void) t_close(fd);
270 			return (-1);
271 		}
272 	} else {
273 		if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
274 			syslog(LOG_ERR, "I_PUSH of CONS rpcmod failed: %m");
275 			if (t_close(fd) == -1) {
276 				if (t_errno == TSYSERR) {
277 					syslog(LOG_ERR,
278 						"t_close failed on %d: %m", fd);
279 				} else {
280 					syslog(LOG_ERR,
281 						"t_close failed on %d: %s",
282 						fd, t_errlist[t_errno]);
283 				}
284 			}
285 			return (-1);
286 		}
287 
288 		strioc.ic_cmd = RPC_SERVER;
289 		strioc.ic_dp = (char *)0;
290 		strioc.ic_len = 0;
291 		strioc.ic_timout = -1;
292 		/* Tell CONS rpcmod to act like a server stream. */
293 		if (ioctl(fd, I_STR, &strioc) < 0) {
294 			syslog(LOG_ERR, "CONS rpcmod set-up ioctl failed: %m");
295 			if (t_close(fd) == -1) {
296 				if (t_errno == TSYSERR) {
297 					syslog(LOG_ERR,
298 						"t_close failed on %d: %m", fd);
299 				} else {
300 					syslog(LOG_ERR,
301 						"t_close failed on %d: %s",
302 						fd, t_errlist[t_errno]);
303 				}
304 			}
305 			return (-1);
306 		}
307 	}
308 
309 	/*
310 	 * Re-push timod so that we will still be doing TLI
311 	 * operations on the descriptor.
312 	 */
313 	if (ioctl(fd, I_PUSH, "timod") < 0) {
314 		syslog(LOG_ERR, "I_PUSH of timod failed: %m");
315 		if (t_close(fd) == -1) {
316 			if (t_errno == TSYSERR) {
317 				syslog(LOG_ERR, "t_close failed on %d: %m", fd);
318 			} else {
319 				syslog(LOG_ERR, "t_close failed on %d: %s",
320 				    fd, t_errlist[t_errno]);
321 			}
322 		}
323 		return (-1);
324 	}
325 
326 	return (fd);
327 }
328 
329 
330 void
331 rdcd_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
332 {
333 	int error;
334 
335 	/*
336 	 * Save the error code across syslog(), just in case syslog()
337 	 * gets its own error and, therefore, overwrites errno.
338 	 */
339 	error = errno;
340 	if (t_errno == TSYSERR) {
341 		syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
342 		    tli_name, fd, nconf->nc_proto);
343 	} else {
344 		syslog(LOG_ERR,
345 		    "%s(file descriptor %d/transport %s) TLI error %d",
346 		    tli_name, fd, nconf->nc_proto, t_errno);
347 	}
348 	errno = error;
349 }
350 
351 /*
352  * Called to set up service over a particular transport
353  */
354 void
355 do_one(char *provider, char *proto, struct protob *protobp0,
356 	int (*svc)(int, struct netbuf, struct netconfig *))
357 {
358 	struct netbuf *retaddr;
359 	struct netconfig *retnconf;
360 	struct netbuf addrmask;
361 	int vers;
362 	int sock;
363 
364 	if (provider) {
365 		sock = bind_to_provider(provider, protobp0->serv, &retaddr,
366 		    &retnconf);
367 	} else {
368 		(void) syslog(LOG_ERR,
369 	"Cannot establish %s service over %s: transport setup problem.",
370 		    protobp0->serv, provider ? provider : proto);
371 		return;
372 	}
373 
374 	if (sock == -1) {
375 		if ((Is_ipv6present() &&
376 		(strcmp(provider, "/dev/tcp6") == 0)) ||
377 		(!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
378 			(void) syslog(LOG_ERR,
379 			    "Cannot establish %s service over %s: transport "
380 				"setup problem.",
381 				protobp0->serv, provider ? provider : proto);
382 		return;
383 	}
384 
385 	if (set_addrmask(sock, retnconf, &addrmask) < 0) {
386 		(void) syslog(LOG_ERR,
387 		    "Cannot set address mask for %s", retnconf->nc_netid);
388 		return;
389 	}
390 
391 
392 	/*
393 	 * Register all versions of the programs in the protocol block list
394 	 */
395 	for (vers = protobp0->versmin; vers <= protobp0->versmax; vers++) {
396 		(void) rpcb_unset(protobp0->program, vers, retnconf);
397 		(void) rpcb_set(protobp0->program, vers, retnconf, retaddr);
398 	}
399 
400 	if (retnconf->nc_semantics == NC_TPI_CLTS) {
401 		/* Don't drop core if supporting module(s) aren't loaded. */
402 		(void) signal(SIGSYS, SIG_IGN);
403 
404 		/*
405 		 * svc() doesn't block, it returns success or failure.
406 		 */
407 		if ((*svc)(sock, addrmask, retnconf) < 0) {
408 			(void) syslog(LOG_ERR,
409 "Cannot establish %s service over <file desc. %d, protocol %s> : %m. Exiting",
410 				protobp0->serv, sock, retnconf->nc_proto);
411 			exit(1);
412 		}
413 	}
414 	/*
415 	 * We successfully set up the server over this transport.
416 	 * Add this descriptor to the one being polled on.
417 	 */
418 	add_to_poll_list(sock, retnconf);
419 }
420 
421 /*
422  * Set up the SNDR/ncall-ip service over all the available transports.
423  * Returns -1 for failure, 0 for success.
424  */
425 int
426 do_all(struct protob *protobp,
427 	int (*svc)(int, struct netbuf, struct netconfig *))
428 {
429 	struct netconfig *nconf;
430 	NCONF_HANDLE *nc;
431 
432 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
433 		syslog(LOG_ERR, "setnetconfig failed: %m");
434 		return (-1);
435 	}
436 	while (nconf = getnetconfig(nc)) {
437 		if ((nconf->nc_flag & NC_VISIBLE) &&
438 		    strcmp(nconf->nc_protofmly, "loopback") != 0 &&
439 		    OK_TPI_TYPE(nconf))
440 			do_one(nconf->nc_device, nconf->nc_proto,
441 				protobp, svc);
442 	}
443 	(void) endnetconfig(nc);
444 	return (0);
445 }
446 
447 /*
448  * Read the /etc/default/sndr configuration file to determine if the
449  * client has been configured for number of threads, backlog or transport
450  * provider.
451  */
452 
453 static void
454 read_default(void)
455 {
456 	char *defval, *tmp_str;
457 	int errno;
458 	int tmp;
459 
460 	/* Fail silently if error in opening the default rdc config file */
461 	if ((defopen(RDCADMIN)) == 0) {
462 		if ((defval = defread("SNDR_THREADS=")) != NULL) {
463 			errno = 0;
464 			tmp = strtol(defval, (char **)NULL, 10);
465 			if (errno == 0) {
466 				max_conns_allowed = tmp;
467 			}
468 		}
469 		if ((defval = defread("SNDR_LISTEN_BACKLOG=")) != NULL) {
470 			errno = 0;
471 			tmp = strtol(defval, (char **)NULL, 10);
472 			if (errno == 0) {
473 				listen_backlog = tmp;
474 			}
475 		}
476 		if ((defval = defread("SNDR_TRANSPORT=")) != NULL) {
477 			errno = 0;
478 			tmp_str = strdup(defval);
479 			if (errno == 0) {
480 				trans_provider = tmp_str;
481 			}
482 		}
483 		/* close defaults file */
484 		defopen(NULL);
485 	}
486 }
487 #ifdef lint
488 int
489 sndrd_lintmain(int ac, char **av)
490 #else
491 int
492 main(int ac, char **av)
493 #endif
494 {
495 	const char *dir = "/";
496 	int allflag = 0;
497 	int pid;
498 	int i, rc;
499 	struct protob *protobp0, *protobp;
500 	char **providerp;
501 	char *required;
502 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
503 	int maxservers;
504 #endif
505 
506 	(void) setlocale(LC_ALL, "");
507 #ifdef	__NCALL__
508 	(void) textdomain("ncall");
509 #else
510 	(void) textdomain("rdc");
511 #endif
512 
513 	progname = basename(av[0]);
514 
515 #ifdef	__NCALL__
516 	rc = ncall_check_release(&required);
517 #else
518 	rc = rdc_check_release(&required);
519 #endif
520 	if (rc < 0) {
521 		(void) fprintf(stderr,
522 		    gettext("%s: unable to determine the current "
523 		    "Solaris release: %s\n"), progname, strerror(errno));
524 		exit(1);
525 	} else if (rc == FALSE) {
526 		(void) fprintf(stderr,
527 		    gettext("%s: incorrect Solaris release (requires %s)\n"),
528 		    progname, required);
529 		exit(1);
530 	}
531 
532 	openlog(progname, LOG_PID|LOG_CONS, LOG_DAEMON);
533 	read_default();
534 
535 	/*
536 	 * Usage: <progname> [-c <number of threads>] [-t protocol] \
537 	 *		[-d] [-l <listen backlog>]
538 	 */
539 	while ((i = getopt(ac, av, "ac:t:dl:")) != EOF) {
540 		switch (i) {
541 			case 'a':
542 				allflag = 1;
543 				break;
544 			case 'c':
545 				max_conns_allowed = atoi(optarg);
546 				if (max_conns_allowed <= 0)
547 					max_conns_allowed = 16;
548 				break;
549 
550 			case 'd':
551 				debugflg++;
552 				break;
553 
554 			case 't':
555 				trans_provider = optarg;
556 				break;
557 
558 			case 'l':
559 				listen_backlog = atoi(optarg);
560 				if (listen_backlog < 0)
561 					listen_backlog = 32;
562 				break;
563 
564 			default:
565 				syslog(LOG_ERR,
566 				    "Usage: %s [-c <number of threads>] "
567 				    "[-d] [-t protocol] "
568 				    "[-l <listen backlog>]\n", progname);
569 				exit(1);
570 				break;
571 		}
572 	}
573 
574 	if (chroot(dir) < 0) {
575 		syslog(LOG_ERR, "chroot failed: %m");
576 		exit(1);
577 	}
578 
579 	if (chdir(dir) < 0) {
580 		syslog(LOG_ERR, "chdir failed: %m");
581 		exit(1);
582 	}
583 
584 	if (!debugflg) {
585 		pid = fork();
586 		if (pid < 0) {
587 			syslog(LOG_ERR, "Fork failed\n");
588 			exit(1);
589 		}
590 		if (pid != 0)
591 			exit(0);
592 
593 		/*
594 		 * Close existing file descriptors, open "/dev/null" as
595 		 * standard input, output, and error, and detach from
596 		 * controlling terminal.
597 		 */
598 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
599 		/* use closefrom(3C) from PSARC/2000/193 when possible */
600 		closefrom(0);
601 #else
602 		for (i = 0; i < _NFILE; i++)
603 			(void) close(i);
604 #endif
605 		(void) open("/dev/null", O_RDONLY);
606 		(void) open("/dev/null", O_WRONLY);
607 		(void) dup(1);
608 		(void) setsid();
609 
610 		/*
611 		 * ignore all signals apart from SIGTERM.
612 		 */
613 		for (i = 1; i < _sys_nsig; i++)
614 			(void) sigset(i, SIG_IGN);
615 
616 		(void) sigset(SIGTERM, SIG_DFL);
617 	}
618 
619 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
620 	/*
621 	 * Set up kernel RPC thread pool for the SNDR/ncall-ip server.
622 	 */
623 	maxservers = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
624 	if (sndrsvcpool(maxservers)) {
625 		(void) syslog(LOG_ERR,
626 		    "Can't set up kernel %s service: %m. Exiting", progname);
627 		exit(1);
628 	}
629 
630 	/*
631 	 * Set up blocked thread to do LWP creation on behalf of the kernel.
632 	 */
633 	if (svcwait(RDC_SVCPOOL_ID)) {
634 		(void) syslog(LOG_ERR,
635 		    "Can't set up %s pool creator: %m, Exiting", progname);
636 		exit(1);
637 	}
638 #endif
639 
640 	/*
641 	 * Build a protocol block list for registration.
642 	 */
643 	protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
644 	protobp->serv = RDC_SVC_NAME;
645 	protobp->versmin = RDC_VERS_MIN;
646 	protobp->versmax = RDC_VERS_MAX;
647 	protobp->program = RDC_PROGRAM;
648 	protobp->next = (struct protob *)NULL;
649 
650 	if (allflag) {
651 		if (do_all(protobp0, rdcsvc) == -1)
652 			exit(1);
653 	} else if (trans_provider)
654 		do_one(trans_provider, NULL, protobp0, rdcsvc);
655 	else {
656 		for (providerp = defaultproviders;
657 		    *providerp != NULL; providerp++) {
658 			trans_provider = *providerp;
659 			do_one(trans_provider, NULL, protobp0, rdcsvc);
660 		}
661 	}
662 
663 done:
664 	free(protobp);
665 
666 	end_listen_fds = num_fds;
667 	/*
668 	 * Poll for non-data control events on the transport descriptors.
669 	 */
670 	poll_for_action();
671 
672 	syslog(LOG_ERR, "%s fatal server error\n", progname);
673 
674 	return (-1);
675 }
676 
677 static int
678 reuseaddr(int fd)
679 {
680 	struct t_optmgmt req, resp;
681 	struct opthdr *opt;
682 	char reqbuf[128];
683 	int *ip;
684 
685 	/* LINTED pointer alignment */
686 	opt = (struct opthdr *)reqbuf;
687 	opt->level = SOL_SOCKET;
688 	opt->name = SO_REUSEADDR;
689 	opt->len = sizeof (int);
690 
691 	/* LINTED pointer alignment */
692 	ip = (int *)&reqbuf[sizeof (struct opthdr)];
693 	*ip = 1;
694 
695 	req.flags = T_NEGOTIATE;
696 	req.opt.len = sizeof (struct opthdr) + opt->len;
697 	req.opt.buf = (char *)opt;
698 
699 	resp.flags = 0;
700 	resp.opt.buf = reqbuf;
701 	resp.opt.maxlen = sizeof (reqbuf);
702 
703 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
704 		if (t_errno == TSYSERR) {
705 			syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %m\n");
706 		} else {
707 			syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %s\n",
708 			    t_errlist[t_errno]);
709 		}
710 		return (-1);
711 	}
712 	return (0);
713 }
714 
715 /*
716  * poll on the open transport descriptors for events and errors.
717  */
718 void
719 poll_for_action(void)
720 {
721 	int nfds;
722 	int i;
723 
724 	/*
725 	 * Keep polling until all transports have been closed. When this
726 	 * happens, we return.
727 	 */
728 	while ((int)num_fds > 0) {
729 		nfds = poll(poll_array, num_fds, INFTIM);
730 		switch (nfds) {
731 		case 0:
732 			continue;
733 
734 		case -1:
735 			/*
736 			 * Some errors from poll could be
737 			 * due to temporary conditions, and we try to
738 			 * be robust in the face of them. Other
739 			 * errors (should never happen in theory)
740 			 * are fatal (eg. EINVAL, EFAULT).
741 			 */
742 			switch (errno) {
743 			case EINTR:
744 			    continue;
745 
746 			case EAGAIN:
747 			case ENOMEM:
748 				(void) sleep(10);
749 				continue;
750 
751 			default:
752 				(void) syslog(LOG_ERR,
753 				    "poll failed: %m. Exiting");
754 				exit(1);
755 			}
756 		default:
757 			break;
758 		}
759 
760 		/*
761 		 * Go through the poll list looking for events.
762 		 */
763 		for (i = 0; i < num_fds && nfds > 0; i++) {
764 			if (poll_array[i].revents) {
765 				nfds--;
766 				/*
767 				 * We have a message, so try to read it.
768 				 * Record the error return in errno,
769 				 * so that syslog(LOG_ERR, "...%m")
770 				 * dumps the corresponding error string.
771 				 */
772 				if (conn_polled[i].nc.nc_semantics ==
773 				    NC_TPI_CLTS) {
774 					errno = do_poll_clts_action(
775 					    poll_array[i].fd, i);
776 				} else {
777 					errno = do_poll_cots_action(
778 					    poll_array[i].fd, i);
779 				}
780 
781 				if (errno == 0)
782 					continue;
783 				/*
784 				 * Most returned error codes mean that there is
785 				 * fatal condition which we can only deal with
786 				 * by closing the transport.
787 				 */
788 				if (errno != EAGAIN && errno != ENOMEM) {
789 					(void) syslog(LOG_ERR,
790 					    "Error (%m) reading descriptor %d"
791 					    "/transport %s. Closing it.",
792 					    poll_array[i].fd,
793 					    conn_polled[i].nc.nc_proto);
794 					(void) t_close(poll_array[i].fd);
795 					remove_from_poll_list(poll_array[i].fd);
796 				} else if (errno == ENOMEM)
797 					(void) sleep(5);
798 			}
799 		}
800 	}
801 
802 	(void) syslog(LOG_ERR,
803 	    "All transports have been closed with errors. Exiting.");
804 }
805 
806 /*
807  * Allocate poll/transport array entries for this descriptor.
808  */
809 static void
810 add_to_poll_list(int fd, struct netconfig *nconf)
811 {
812 	static int poll_array_size = 0;
813 
814 	/*
815 	 * If the arrays are full, allocate new ones.
816 	 */
817 	if (num_fds == poll_array_size) {
818 		struct pollfd *tpa;
819 		struct conn_entry *tnp;
820 
821 		if (poll_array_size != 0) {
822 			tpa = poll_array;
823 			tnp = conn_polled;
824 		} else
825 			tpa = (struct pollfd *)0;
826 
827 		poll_array_size += POLL_ARRAY_INC_SIZE;
828 
829 		/*
830 		 * Allocate new arrays.
831 		 */
832 		poll_array = (struct pollfd *)
833 		    malloc(poll_array_size * sizeof (struct pollfd) + 256);
834 		conn_polled = (struct conn_entry *)
835 		    malloc(poll_array_size * sizeof (struct conn_entry) + 256);
836 		if (poll_array == (struct pollfd *)NULL ||
837 		    conn_polled == (struct conn_entry *)NULL) {
838 			syslog(LOG_ERR, "malloc failed for poll array");
839 			exit(1);
840 		}
841 
842 		/*
843 		 * Copy the data of the old ones into new arrays, and
844 		 * free the old ones.
845 		 * num_fds is guaranteed to be less than
846 		 * poll_array_size, so this memcpy is safe.
847 		 */
848 		if (tpa) {
849 			(void) memcpy((void *)poll_array, (void *)tpa,
850 				num_fds * sizeof (struct pollfd));
851 			(void) memcpy((void *)conn_polled, (void *)tnp,
852 				num_fds * sizeof (struct conn_entry));
853 			free((void *)tpa);
854 			free((void *)tnp);
855 		}
856 	}
857 
858 	/*
859 	 * Set the descriptor and event list. All possible events are
860 	 * polled for.
861 	 */
862 	poll_array[num_fds].fd = fd;
863 	poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
864 
865 	/*
866 	 * Copy the transport data over too.
867 	 */
868 	conn_polled[num_fds].nc = *nconf;	/* structure copy */
869 	conn_polled[num_fds].closing = 0;
870 
871 	/*
872 	 * Set the descriptor to non-blocking. Avoids a race
873 	 * between data arriving on the stream and then having it
874 	 * flushed before we can read it.
875 	 */
876 	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
877 		(void) syslog(LOG_ERR,
878 		    "fcntl(file desc. %d/transport %s, F_SETFL, "
879 		    "O_NONBLOCK): %m. Exiting",
880 		    num_fds, nconf->nc_proto);
881 		exit(1);
882 	}
883 
884 	/*
885 	 * Count this descriptor.
886 	 */
887 	++num_fds;
888 }
889 
890 static void
891 remove_from_poll_list(int fd)
892 {
893 	int i;
894 	int num_to_copy;
895 
896 	for (i = 0; i < num_fds; i++) {
897 		if (poll_array[i].fd == fd) {
898 			--num_fds;
899 			num_to_copy = num_fds - i;
900 			(void) memcpy((void *)&poll_array[i],
901 			    (void *)&poll_array[i+1],
902 			    num_to_copy * sizeof (struct pollfd));
903 			(void) memset((void *)&poll_array[num_fds], 0,
904 			    sizeof (struct pollfd));
905 			(void) memcpy((void *)&conn_polled[i],
906 			    (void *)&conn_polled[i+1],
907 			    num_to_copy * sizeof (struct conn_entry));
908 			(void) memset((void *)&conn_polled[num_fds], 0,
909 			    sizeof (struct conn_entry));
910 			return;
911 		}
912 	}
913 	syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
914 
915 }
916 
917 static void
918 conn_close_oldest(void)
919 {
920 	int fd;
921 	int i1;
922 
923 	/*
924 	 * Find the oldest connection that is not already in the
925 	 * process of shutting down.
926 	 */
927 	for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
928 		if (i1 >= num_fds)
929 			return;
930 		if (conn_polled[i1].closing == 0)
931 			break;
932 	}
933 #ifdef DEBUG
934 	(void) printf("too many connections (%d), releasing oldest (%d)\n",
935 	    num_conns, poll_array[i1].fd);
936 #else
937 	syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
938 	    num_conns, poll_array[i1].fd);
939 #endif
940 	fd = poll_array[i1].fd;
941 	if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
942 		/*
943 		 * For politeness, send a T_DISCON_REQ to the transport
944 		 * provider.  We close the stream anyway.
945 		 */
946 		(void) t_snddis(fd, (struct t_call *)0);
947 		num_conns--;
948 		remove_from_poll_list(fd);
949 		(void) t_close(fd);
950 	} else {
951 		/*
952 		 * For orderly release, we do not close the stream
953 		 * until the T_ORDREL_IND arrives to complete
954 		 * the handshake.
955 		 */
956 		if (t_sndrel(fd) == 0)
957 			conn_polled[i1].closing = 1;
958 	}
959 }
960 
961 static boolean_t
962 conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
963 {
964 	struct conn_ind	*conn;
965 	struct conn_ind	*next_conn;
966 
967 	conn = (struct conn_ind *)malloc(sizeof (*conn));
968 	if (conn == NULL) {
969 		syslog(LOG_ERR, "malloc for listen indication failed");
970 		return (FALSE);
971 	}
972 
973 	/* LINTED pointer alignment */
974 	conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
975 	if (conn->conn_call == NULL) {
976 		free((char *)conn);
977 		rdcd_log_tli_error("t_alloc", fd, nconf);
978 		return (FALSE);
979 	}
980 
981 	if (t_listen(fd, conn->conn_call) == -1) {
982 		rdcd_log_tli_error("t_listen", fd, nconf);
983 		(void) t_free((char *)conn->conn_call, T_CALL);
984 		free((char *)conn);
985 		return (FALSE);
986 	}
987 
988 	if (conn->conn_call->udata.len > 0) {
989 		syslog(LOG_WARNING,
990 		    "rejecting inbound connection(%s) with %d bytes "
991 		    "of connect data",
992 		    nconf->nc_proto, conn->conn_call->udata.len);
993 
994 		conn->conn_call->udata.len = 0;
995 		(void) t_snddis(fd, conn->conn_call);
996 		(void) t_free((char *)conn->conn_call, T_CALL);
997 		free((char *)conn);
998 		return (FALSE);
999 	}
1000 
1001 	if ((next_conn = *connp) != NULL) {
1002 		next_conn->conn_prev->conn_next = conn;
1003 		conn->conn_next = next_conn;
1004 		conn->conn_prev = next_conn->conn_prev;
1005 		next_conn->conn_prev = conn;
1006 	} else {
1007 		conn->conn_next = conn;
1008 		conn->conn_prev = conn;
1009 		*connp = conn;
1010 	}
1011 	return (TRUE);
1012 }
1013 
1014 static int
1015 discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1016 {
1017 	struct conn_ind	*conn;
1018 	struct t_discon	discon;
1019 
1020 	discon.udata.buf = (char *)0;
1021 	discon.udata.maxlen = 0;
1022 	if (t_rcvdis(fd, &discon) == -1) {
1023 		rdcd_log_tli_error("t_rcvdis", fd, nconf);
1024 		return (-1);
1025 	}
1026 
1027 	conn = *connp;
1028 	if (conn == NULL)
1029 		return (0);
1030 
1031 	do {
1032 		if (conn->conn_call->sequence == discon.sequence) {
1033 			if (conn->conn_next == conn)
1034 				*connp = (struct conn_ind *)0;
1035 			else {
1036 				if (conn == *connp) {
1037 					*connp = conn->conn_next;
1038 				}
1039 				conn->conn_next->conn_prev = conn->conn_prev;
1040 				conn->conn_prev->conn_next = conn->conn_next;
1041 			}
1042 			free((char *)conn);
1043 			break;
1044 		}
1045 		conn = conn->conn_next;
1046 	} while (conn != *connp);
1047 
1048 	return (0);
1049 }
1050 
1051 static void
1052 cots_listen_event(int fd, int conn_index)
1053 {
1054 	struct t_call *call;
1055 	struct conn_ind	*conn;
1056 	struct conn_ind	*conn_head;
1057 	int event;
1058 	struct netconfig *nconf = &conn_polled[conn_index].nc;
1059 	int new_fd;
1060 	struct netbuf addrmask;
1061 	int ret = 0;
1062 
1063 	conn_head = (struct conn_ind *)0;
1064 	(void) conn_get(fd, nconf, &conn_head);
1065 
1066 	while ((conn = conn_head) != NULL) {
1067 		conn_head = conn->conn_next;
1068 		if (conn_head == conn)
1069 			conn_head = (struct conn_ind *)0;
1070 		else {
1071 			conn_head->conn_prev = conn->conn_prev;
1072 			conn->conn_prev->conn_next = conn_head;
1073 		}
1074 		call = conn->conn_call;
1075 		free((char *)conn);
1076 
1077 		/*
1078 		 * If we have already accepted the maximum number of
1079 		 * connections allowed on the command line, then drop
1080 		 * the oldest connection (for any protocol) before
1081 		 * accepting the new connection.  Unless explicitly
1082 		 * set on the command line, max_conns_allowed is -1.
1083 		 */
1084 		if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
1085 			conn_close_oldest();
1086 
1087 		/*
1088 		 * Create a new transport endpoint for the same proto as
1089 		 * the listener.
1090 		 */
1091 		new_fd = rdc_transport_open(nconf);
1092 		if (new_fd == -1) {
1093 			call->udata.len = 0;
1094 			(void) t_snddis(fd, call);
1095 			(void) t_free((char *)call, T_CALL);
1096 			syslog(LOG_ERR, "Cannot establish transport over %s",
1097 			    nconf->nc_device);
1098 			continue;
1099 		}
1100 
1101 		/* Bind to a generic address/port for the accepting stream. */
1102 		if (t_bind(new_fd, (struct t_bind *)NULL,
1103 		    (struct t_bind *)NULL) == -1) {
1104 			rdcd_log_tli_error("t_bind", new_fd, nconf);
1105 			call->udata.len = 0;
1106 			(void) t_snddis(fd, call);
1107 			(void) t_free((char *)call, T_CALL);
1108 			(void) t_close(new_fd);
1109 			continue;
1110 		}
1111 
1112 		while (t_accept(fd, new_fd, call) == -1) {
1113 			if (t_errno != TLOOK) {
1114 				rdcd_log_tli_error("t_accept", fd, nconf);
1115 				call->udata.len = 0;
1116 				(void) t_snddis(fd, call);
1117 				(void) t_free((char *)call, T_CALL);
1118 				(void) t_close(new_fd);
1119 				goto do_next_conn;
1120 			}
1121 			while (event = t_look(fd)) {
1122 				switch (event) {
1123 				case T_LISTEN:
1124 #ifdef DEBUG
1125 					(void) printf(
1126 "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
1127 #endif
1128 					(void) conn_get(fd, nconf, &conn_head);
1129 					continue;
1130 
1131 				case T_DISCONNECT:
1132 #ifdef DEBUG
1133 					(void) printf(
1134 	"cots_listen_event(%s): T_DISCONNECT during accept processing\n",
1135 						nconf->nc_proto);
1136 #endif
1137 					(void) discon_get(fd, nconf,
1138 					    &conn_head);
1139 					continue;
1140 
1141 				default:
1142 					syslog(LOG_ERR,
1143 					    "unexpected event 0x%x during "
1144 					    "accept processing (%s)",
1145 					    event, nconf->nc_proto);
1146 					call->udata.len = 0;
1147 					(void) t_snddis(fd, call);
1148 					(void) t_free((char *)call, T_CALL);
1149 					(void) t_close(new_fd);
1150 					goto do_next_conn;
1151 				}
1152 			}
1153 		}
1154 
1155 		if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
1156 			(void) syslog(LOG_ERR, "Cannot set address mask for %s",
1157 			    nconf->nc_netid);
1158 			return;
1159 		}
1160 
1161 		/* Tell KRPC about the new stream. */
1162 		ret = (*Mysvc)(new_fd, addrmask, nconf);
1163 		if (ret < 0) {
1164 			syslog(LOG_ERR,
1165 			    "unable to register with kernel rpc: %m");
1166 			free(addrmask.buf);
1167 			(void) t_snddis(new_fd, (struct t_call *)0);
1168 			(void) t_free((char *)call, T_CALL);
1169 			(void) t_close(new_fd);
1170 			goto do_next_conn;
1171 		}
1172 
1173 		free(addrmask.buf);
1174 		(void) t_free((char *)call, T_CALL);
1175 
1176 		/*
1177 		 * Poll on the new descriptor so that we get disconnect
1178 		 * and orderly release indications.
1179 		 */
1180 		num_conns++;
1181 		add_to_poll_list(new_fd, nconf);
1182 
1183 		/* Reset nconf in case it has been moved. */
1184 		nconf = &conn_polled[conn_index].nc;
1185 do_next_conn:;
1186 	}
1187 }
1188 
1189 static int
1190 do_poll_cots_action(int fd, int conn_index)
1191 {
1192 	char buf[256];
1193 	int event;
1194 	int i1;
1195 	int flags;
1196 	struct conn_entry *connent = &conn_polled[conn_index];
1197 	struct netconfig *nconf = &(connent->nc);
1198 	const char *errorstr;
1199 
1200 	while (event = t_look(fd)) {
1201 		switch (event) {
1202 		case T_LISTEN:
1203 #ifdef DEBUG
1204 	(void) printf("do_poll_cots_action(%s, %d): T_LISTEN event\n",
1205 	    nconf->nc_proto, fd);
1206 #endif
1207 			cots_listen_event(fd, conn_index);
1208 			break;
1209 
1210 		case T_DATA:
1211 #ifdef DEBUG
1212 	(void) printf("do_poll_cots_action(%d, %s): T_DATA event\n",
1213 		fd, nconf->nc_proto);
1214 #endif
1215 			/*
1216 			 * Receive a private notification from CONS rpcmod.
1217 			 */
1218 			i1 = t_rcv(fd, buf, sizeof (buf), &flags);
1219 			if (i1 == -1) {
1220 				syslog(LOG_ERR, "t_rcv failed");
1221 				break;
1222 			}
1223 			if (i1 < sizeof (int))
1224 				break;
1225 			i1 = BE32_TO_U32(buf);
1226 			if (i1 == 1 || i1 == 2) {
1227 				/*
1228 				 * This connection has been idle for too long,
1229 				 * so release it as politely as we can.  If we
1230 				 * have already initiated an orderly release
1231 				 * and we get notified that the stream is
1232 				 * still idle, pull the plug.  This prevents
1233 				 * hung connections from continuing to consume
1234 				 * resources.
1235 				 */
1236 #ifdef DEBUG
1237 (void) printf("do_poll_cots_action(%s, %d): ", nconf->nc_proto, fd);
1238 (void) printf("initiating orderly release of idle connection\n");
1239 #endif
1240 				if (nconf->nc_semantics == NC_TPI_COTS ||
1241 				    connent->closing != 0) {
1242 					(void) t_snddis(fd, (struct t_call *)0);
1243 					goto fdclose;
1244 				}
1245 				/*
1246 				 * For NC_TPI_COTS_ORD, the stream is closed
1247 				 * and removed from the poll list when the
1248 				 * T_ORDREL is received from the provider.  We
1249 				 * don't wait for it here because it may take
1250 				 * a while for the transport to shut down.
1251 				 */
1252 				if (t_sndrel(fd) == -1) {
1253 					syslog(LOG_ERR,
1254 					"unable to send orderly release %m");
1255 				}
1256 				connent->closing = 1;
1257 			} else
1258 				syslog(LOG_ERR,
1259 				    "unexpected event from CONS rpcmod %d", i1);
1260 			break;
1261 
1262 		case T_ORDREL:
1263 #ifdef DEBUG
1264 	(void) printf("do_poll_cots_action(%s, %d): T_ORDREL event\n",
1265 		nconf->nc_proto, fd);
1266 #endif
1267 			/* Perform an orderly release. */
1268 			if (t_rcvrel(fd) == 0) {
1269 				/* T_ORDREL on listen fd's should be ignored */
1270 				if (!is_listen_fd_index(fd)) {
1271 					(void) t_sndrel(fd);
1272 					goto fdclose;
1273 				}
1274 				break;
1275 
1276 			} else if (t_errno == TLOOK) {
1277 				break;
1278 			} else {
1279 				rdcd_log_tli_error("t_rcvrel", fd, nconf);
1280 				/*
1281 				 * check to make sure we do not close
1282 				 * listen fd
1283 				 */
1284 				if (!is_listen_fd_index(fd))
1285 					break;
1286 				else
1287 					goto fdclose;
1288 			}
1289 
1290 		case T_DISCONNECT:
1291 #ifdef DEBUG
1292 (void) printf("do_poll_cots_action(%s, %d): T_DISCONNECT event\n",
1293 nconf->nc_proto, fd);
1294 #endif
1295 			if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
1296 				rdcd_log_tli_error("t_rcvdis", fd, nconf);
1297 
1298 			/*
1299 			 * T_DISCONNECT on listen fd's should be ignored.
1300 			 */
1301 			if (!is_listen_fd_index(fd))
1302 				break;
1303 			else
1304 				goto fdclose;
1305 
1306 		case T_ERROR:
1307 		default:
1308 			if (event == T_ERROR || t_errno == TSYSERR) {
1309 			    if ((errorstr = strerror(errno)) == NULL) {
1310 				(void) snprintf(buf, sizeof (buf),
1311 				    "Unknown error num %d", errno);
1312 				errorstr = (const char *)buf;
1313 			    }
1314 			} else if (event == -1)
1315 				errorstr = t_strerror(t_errno);
1316 			else
1317 				errorstr = "";
1318 #ifdef DEBUG
1319 			syslog(LOG_ERR,
1320 			    "unexpected TLI event (0x%x) on "
1321 			    "connection-oriented transport(%s, %d):%s",
1322 			    event, nconf->nc_proto, fd, errorstr);
1323 #endif
1324 
1325 fdclose:
1326 			num_conns--;
1327 			remove_from_poll_list(fd);
1328 			(void) t_close(fd);
1329 			return (0);
1330 		}
1331 	}
1332 
1333 	return (0);
1334 }
1335 
1336 
1337 /*
1338  * Called to read and interpret the event on a connectionless descriptor.
1339  * Returns 0 if successful, or a UNIX error code if failure.
1340  */
1341 static int
1342 do_poll_clts_action(int fd, int conn_index)
1343 {
1344 	int error;
1345 	int ret;
1346 	int flags;
1347 	struct netconfig *nconf = &conn_polled[conn_index].nc;
1348 	static struct t_unitdata *unitdata = NULL;
1349 	static struct t_uderr *uderr = NULL;
1350 	static int oldfd = -1;
1351 	struct nd_hostservlist *host = NULL;
1352 	struct strbuf ctl[1], data[1];
1353 	/*
1354 	 * We just need to have some space to consume the
1355 	 * message in the event we can't use the TLI interface to do the
1356 	 * job.
1357 	 *
1358 	 * We flush the message using getmsg(). For the control part
1359 	 * we allocate enough for any TPI header plus 32 bytes for address
1360 	 * and options. For the data part, there is nothing magic about
1361 	 * the size of the array, but 256 bytes is probably better than
1362 	 * 1 byte, and we don't expect any data portion anyway.
1363 	 *
1364 	 * If the array sizes are too small, we handle this because getmsg()
1365 	 * (called to consume the message) will return MOREDATA|MORECTL.
1366 	 * Thus we just call getmsg() until it's read the message.
1367 	 */
1368 	char ctlbuf[sizeof (union T_primitives) + 32];
1369 	char databuf[256];
1370 
1371 	/*
1372 	 * If this is the same descriptor as the last time
1373 	 * do_poll_clts_action was called, we can save some
1374 	 * de-allocation and allocation.
1375 	 */
1376 	if (oldfd != fd) {
1377 		oldfd = fd;
1378 
1379 		if (unitdata) {
1380 			(void) t_free((char *)unitdata, T_UNITDATA);
1381 			unitdata = NULL;
1382 		}
1383 		if (uderr) {
1384 			(void) t_free((char *)uderr, T_UDERROR);
1385 			uderr = NULL;
1386 		}
1387 	}
1388 
1389 	/*
1390 	 * Allocate a unitdata structure for receiving the event.
1391 	 */
1392 	if (unitdata == NULL) {
1393 		/* LINTED pointer alignment */
1394 		unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
1395 		if (unitdata == NULL) {
1396 			if (t_errno == TSYSERR) {
1397 				/*
1398 				 * Save the error code across
1399 				 * syslog(), just in case
1400 				 * syslog() gets its own error
1401 				 * and therefore overwrites errno.
1402 				 */
1403 				error = errno;
1404 				(void) syslog(LOG_ERR,
1405 	"t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
1406 					fd, nconf->nc_proto);
1407 				return (error);
1408 			}
1409 			(void) syslog(LOG_ERR,
1410 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
1411 					fd, nconf->nc_proto, t_errno);
1412 			goto flush_it;
1413 		}
1414 	}
1415 
1416 try_again:
1417 	flags = 0;
1418 
1419 	/*
1420 	 * The idea is we wait for T_UNITDATA_IND's. Of course,
1421 	 * we don't get any, because rpcmod filters them out.
1422 	 * However, we need to call t_rcvudata() to let TLI
1423 	 * tell us we have a T_UDERROR_IND.
1424 	 *
1425 	 * algorithm is:
1426 	 * 	t_rcvudata(), expecting TLOOK.
1427 	 * 	t_look(), expecting T_UDERR.
1428 	 * 	t_rcvuderr(), expecting success (0).
1429 	 * 	expand destination address into ASCII,
1430 	 *	and dump it.
1431 	 */
1432 
1433 	ret = t_rcvudata(fd, unitdata, &flags);
1434 	if (ret == 0 || t_errno == TBUFOVFLW) {
1435 		(void) syslog(LOG_WARNING,
1436 "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
1437 			fd, nconf->nc_proto, unitdata->udata.len);
1438 
1439 		/*
1440 		 * Even though we don't expect any data, in case we do,
1441 		 * keep reading until there is no more.
1442 		 */
1443 		if (flags & T_MORE)
1444 			goto try_again;
1445 
1446 		return (0);
1447 	}
1448 
1449 	switch (t_errno) {
1450 	case TNODATA:
1451 		return (0);
1452 	case TSYSERR:
1453 		/*
1454 		 * System errors are returned to caller.
1455 		 * Save the error code across
1456 		 * syslog(), just in case
1457 		 * syslog() gets its own error
1458 		 * and therefore overwrites errno.
1459 		 */
1460 		error = errno;
1461 		(void) syslog(LOG_ERR,
1462 			"t_rcvudata(file descriptor %d/transport %s) %m",
1463 			fd, nconf->nc_proto);
1464 		return (error);
1465 	case TLOOK:
1466 		break;
1467 	default:
1468 		(void) syslog(LOG_ERR,
1469 		"t_rcvudata(file descriptor %d/transport %s) TLI error %d",
1470 			fd, nconf->nc_proto, t_errno);
1471 		goto flush_it;
1472 	}
1473 
1474 	ret = t_look(fd);
1475 	switch (ret) {
1476 	case 0:
1477 		return (0);
1478 	case -1:
1479 		/*
1480 		 * System errors are returned to caller.
1481 		 */
1482 		if (t_errno == TSYSERR) {
1483 			/*
1484 			 * Save the error code across
1485 			 * syslog(), just in case
1486 			 * syslog() gets its own error
1487 			 * and therefore overwrites errno.
1488 			 */
1489 			error = errno;
1490 			(void) syslog(LOG_ERR,
1491 				"t_look(file descriptor %d/transport %s) %m",
1492 				fd, nconf->nc_proto);
1493 			return (error);
1494 		}
1495 		(void) syslog(LOG_ERR,
1496 			"t_look(file descriptor %d/transport %s) TLI error %d",
1497 			fd, nconf->nc_proto, t_errno);
1498 		goto flush_it;
1499 	case T_UDERR:
1500 		break;
1501 	default:
1502 		(void) syslog(LOG_WARNING,
1503 	"t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
1504 			fd, nconf->nc_proto, ret, T_UDERR);
1505 	}
1506 
1507 	if (uderr == NULL) {
1508 		/* LINTED pointer alignment */
1509 		uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
1510 		if (uderr == NULL) {
1511 			if (t_errno == TSYSERR) {
1512 				/*
1513 				 * Save the error code across
1514 				 * syslog(), just in case
1515 				 * syslog() gets its own error
1516 				 * and therefore overwrites errno.
1517 				 */
1518 				error = errno;
1519 				(void) syslog(LOG_ERR,
1520 	"t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
1521 					fd, nconf->nc_proto);
1522 				return (error);
1523 			}
1524 			(void) syslog(LOG_ERR,
1525 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
1526 				fd, nconf->nc_proto, t_errno);
1527 			goto flush_it;
1528 		}
1529 	}
1530 
1531 	ret = t_rcvuderr(fd, uderr);
1532 	if (ret == 0) {
1533 
1534 		/*
1535 		 * Save the datagram error in errno, so that the
1536 		 * %m argument to syslog picks up the error string.
1537 		 */
1538 		errno = uderr->error;
1539 
1540 		/*
1541 		 * Log the datagram error, then log the host that
1542 		 * probably triggerred. Cannot log both in the
1543 		 * same transaction because of packet size limitations
1544 		 * in /dev/log.
1545 		 */
1546 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1547 		    "%s response over <file descriptor %d/transport %s> "
1548 		    "generated error: %m",
1549 		    progname, fd, nconf->nc_proto);
1550 
1551 		/*
1552 		 * Try to map the client's address back to a
1553 		 * name.
1554 		 */
1555 		ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
1556 		if (ret != -1 && host && host->h_cnt > 0 &&
1557 		    host->h_hostservs) {
1558 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1559 		    "Bad %s response was sent to client with "
1560 		    "host name: %s; service port: %s",
1561 		    progname, host->h_hostservs->h_host,
1562 		    host->h_hostservs->h_serv);
1563 		} else {
1564 			int i, j;
1565 			char *buf;
1566 			char *hex = "0123456789abcdef";
1567 
1568 			/*
1569 			 * Mapping failed, print the whole thing
1570 			 * in ASCII hex.
1571 			 */
1572 			buf = (char *)malloc(uderr->addr.len * 2 + 1);
1573 			for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
1574 				buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
1575 				buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
1576 			}
1577 			buf[j] = '\0';
1578 			(void) syslog((errno == ECONNREFUSED) ?
1579 			    LOG_DEBUG : LOG_WARNING,
1580 			    "Bad %s response was sent to client with "
1581 			    "transport address: 0x%s",
1582 			    progname, buf);
1583 			free((void *)buf);
1584 		}
1585 
1586 		if (ret == 0 && host != NULL)
1587 			netdir_free((void *)host, ND_HOSTSERVLIST);
1588 		return (0);
1589 	}
1590 
1591 	switch (t_errno) {
1592 	case TNOUDERR:
1593 		goto flush_it;
1594 	case TSYSERR:
1595 		/*
1596 		 * System errors are returned to caller.
1597 		 * Save the error code across
1598 		 * syslog(), just in case
1599 		 * syslog() gets its own error
1600 		 * and therefore overwrites errno.
1601 		 */
1602 		error = errno;
1603 		(void) syslog(LOG_ERR,
1604 			"t_rcvuderr(file descriptor %d/transport %s) %m",
1605 			fd, nconf->nc_proto);
1606 		return (error);
1607 	default:
1608 		(void) syslog(LOG_ERR,
1609 		"t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
1610 			fd, nconf->nc_proto, t_errno);
1611 		goto flush_it;
1612 	}
1613 
1614 flush_it:
1615 	/*
1616 	 * If we get here, then we could not cope with whatever message
1617 	 * we attempted to read, so flush it. If we did read a message,
1618 	 * and one isn't present, that is all right, because fd is in
1619 	 * nonblocking mode.
1620 	 */
1621 	(void) syslog(LOG_ERR,
1622 	"Flushing one input message from <file descriptor %d/transport %s>",
1623 		fd, nconf->nc_proto);
1624 
1625 	/*
1626 	 * Read and discard the message. Do this this until there is
1627 	 * no more control/data in the message or until we get an error.
1628 	 */
1629 	do {
1630 		ctl->maxlen = sizeof (ctlbuf);
1631 		ctl->buf = ctlbuf;
1632 		data->maxlen = sizeof (databuf);
1633 		data->buf = databuf;
1634 		flags = 0;
1635 		ret = getmsg(fd, ctl, data, &flags);
1636 		if (ret == -1)
1637 			return (errno);
1638 	} while (ret != 0);
1639 
1640 	return (0);
1641 }
1642 
1643 /*
1644  * Establish service thread.
1645  */
1646 static int
1647 rdcsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
1648 {
1649 #ifdef	__NCALL__
1650 	struct ncall_svc_args nsa;
1651 #else	/* !__NCALL__ */
1652 	struct rdc_svc_args nsa;
1653 	_rdc_ioctl_t rdc_args = { 0, };
1654 #endif	/* __NCALL__ */
1655 
1656 	nsa.fd = fd;
1657 	nsa.nthr = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
1658 	strncpy(nsa.netid, nconf->nc_netid, sizeof (nsa.netid));
1659 	nsa.addrmask.len = addrmask.len;
1660 	nsa.addrmask.maxlen = addrmask.maxlen;
1661 	nsa.addrmask.buf = addrmask.buf;
1662 
1663 #ifdef	__NCALL__
1664 	return (sndrsys(NC_IOC_SERVER, &nsa));
1665 #else	/* !__NCALL__ */
1666 	rdc_args.arg0 = (long)&nsa;
1667 	return (sndrsys(RDC_ENABLE_SVR, &rdc_args));
1668 #endif	/* __NCALL__ */
1669 }
1670 
1671 
1672 
1673 static int
1674 nofile_increase(int limit)
1675 {
1676 	struct rlimit rl;
1677 
1678 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
1679 		syslog(LOG_ERR,
1680 		    "nofile_increase() getrlimit of NOFILE failed: %m");
1681 		return (-1);
1682 	}
1683 
1684 	if (limit > 0)
1685 		rl.rlim_cur = limit;
1686 	else
1687 		rl.rlim_cur += NOFILE_INC_SIZE;
1688 
1689 	if (rl.rlim_cur > rl.rlim_max && rl.rlim_max != RLIM_INFINITY)
1690 		rl.rlim_max = rl.rlim_cur;
1691 
1692 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
1693 		syslog(LOG_ERR,
1694 		    "nofile_increase() setrlimit of NOFILE to %d failed: %m",
1695 		    rl.rlim_cur);
1696 		return (-1);
1697 	}
1698 
1699 	return (0);
1700 }
1701 
1702 int
1703 rdcd_bindit(struct netconfig *nconf, struct netbuf **addr,
1704     struct nd_hostserv *hs, int backlog)
1705 {
1706 	int fd;
1707 	struct t_bind *ntb;
1708 	struct t_bind tb;
1709 	struct nd_addrlist *addrlist;
1710 	struct t_optmgmt req, resp;
1711 	struct opthdr *opt;
1712 	char reqbuf[128];
1713 
1714 	if ((fd = rdc_transport_open(nconf)) == -1) {
1715 		syslog(LOG_ERR, "cannot establish transport service over %s",
1716 		    nconf->nc_device);
1717 		return (-1);
1718 	}
1719 
1720 	addrlist = (struct nd_addrlist *)NULL;
1721 	if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
1722 		if (strncmp(nconf->nc_netid, "udp", 3) != 0) {
1723 			syslog(LOG_ERR, "Cannot get address for transport "
1724 			    "%s host %s service %s",
1725 			    nconf->nc_netid, hs->h_host, hs->h_serv);
1726 		}
1727 		(void) t_close(fd);
1728 		return (-1);
1729 	}
1730 
1731 	if (strcmp(nconf->nc_proto, "tcp") == 0) {
1732 		/*
1733 		 * If we're running over TCP, then set the
1734 		 * SO_REUSEADDR option so that we can bind
1735 		 * to our preferred address even if previously
1736 		 * left connections exist in FIN_WAIT states.
1737 		 * This is somewhat bogus, but otherwise you have
1738 		 * to wait 2 minutes to restart after killing it.
1739 		 */
1740 		if (reuseaddr(fd) == -1) {
1741 			syslog(LOG_WARNING,
1742 			    "couldn't set SO_REUSEADDR option on transport");
1743 		}
1744 	}
1745 
1746 	if (nconf->nc_semantics == NC_TPI_CLTS)
1747 		tb.qlen = 0;
1748 	else
1749 		tb.qlen = backlog;
1750 
1751 	/* LINTED pointer alignment */
1752 	ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
1753 	if (ntb == (struct t_bind *)NULL) {
1754 		syslog(LOG_ERR, "t_alloc failed:  t_errno %d, %m", t_errno);
1755 		(void) t_close(fd);
1756 		netdir_free((void *)addrlist, ND_ADDRLIST);
1757 		return (-1);
1758 	}
1759 
1760 	tb.addr = *(addrlist->n_addrs);		/* structure copy */
1761 
1762 	if (t_bind(fd, &tb, ntb) == -1) {
1763 		syslog(LOG_ERR, "t_bind failed:  t_errno %d, %m", t_errno);
1764 		(void) t_free((char *)ntb, T_BIND);
1765 		netdir_free((void *)addrlist, ND_ADDRLIST);
1766 		(void) t_close(fd);
1767 		return (-1);
1768 	}
1769 
1770 	/* make sure we bound to the right address */
1771 	if (tb.addr.len != ntb->addr.len ||
1772 	    memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0) {
1773 		syslog(LOG_ERR, "t_bind to wrong address");
1774 		(void) t_free((char *)ntb, T_BIND);
1775 		netdir_free((void *)addrlist, ND_ADDRLIST);
1776 		(void) t_close(fd);
1777 		return (-1);
1778 	}
1779 
1780 	*addr = &ntb->addr;
1781 	netdir_free((void *)addrlist, ND_ADDRLIST);
1782 
1783 	if (strcmp(nconf->nc_proto, "tcp") == 0 ||
1784 	    strcmp(nconf->nc_proto, "tcp6") == 0) {
1785 		/*
1786 		 * Disable the Nagle algorithm on TCP connections.
1787 		 * Connections accepted from this listener will
1788 		 * inherit the listener options.
1789 		 */
1790 
1791 		/* LINTED pointer alignment */
1792 		opt = (struct opthdr *)reqbuf;
1793 		opt->level = IPPROTO_TCP;
1794 		opt->name = TCP_NODELAY;
1795 		opt->len = sizeof (int);
1796 
1797 		/* LINTED pointer alignment */
1798 		*(int *)((char *)opt + sizeof (*opt)) = 1;
1799 
1800 		req.flags = T_NEGOTIATE;
1801 		req.opt.len = sizeof (*opt) + opt->len;
1802 		req.opt.buf = (char *)opt;
1803 		resp.flags = 0;
1804 		resp.opt.buf = reqbuf;
1805 		resp.opt.maxlen = sizeof (reqbuf);
1806 
1807 		if (t_optmgmt(fd, &req, &resp) < 0 ||
1808 		    resp.flags != T_SUCCESS) {
1809 			syslog(LOG_ERR,
1810 	"couldn't set NODELAY option for proto %s: t_errno = %d, %m",
1811 				nconf->nc_proto, t_errno);
1812 		}
1813 	}
1814 
1815 	return (fd);
1816 }
1817 
1818 
1819 /* ARGSUSED */
1820 static int
1821 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
1822 		struct netconfig **retnconf)
1823 {
1824 	struct netconfig *nconf;
1825 	NCONF_HANDLE *nc;
1826 	struct nd_hostserv hs;
1827 
1828 	hs.h_host = HOST_SELF;
1829 	hs.h_serv = RDC_SERVICE;	/* serv_name_to_port_name(serv); */
1830 
1831 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1832 		syslog(LOG_ERR, "setnetconfig failed: %m");
1833 		return (-1);
1834 	}
1835 	while (nconf = getnetconfig(nc)) {
1836 		if (OK_TPI_TYPE(nconf) &&
1837 		    strcmp(nconf->nc_device, provider) == 0) {
1838 			*retnconf = nconf;
1839 			return (rdcd_bindit(nconf, addr, &hs, listen_backlog));
1840 		}
1841 	}
1842 	(void) endnetconfig(nc);
1843 	if ((Is_ipv6present() && (strcmp(provider, "/dev/tcp6") == 0)) ||
1844 	    (!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
1845 		syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
1846 		    provider);
1847 	return (-1);
1848 }
1849 
1850 
1851 /*
1852  * For listen fd's index is always less than end_listen_fds.
1853  * It's value is equal to the number of open file descriptors after the
1854  * last listen end point was opened but before any connection was accepted.
1855  */
1856 static int
1857 is_listen_fd_index(int index)
1858 {
1859 	return (index < end_listen_fds);
1860 }
1861 
1862 
1863 /*
1864  * Create an address mask appropriate for the transport.
1865  * The mask is used to obtain the host-specific part of
1866  * a network address when comparing addresses.
1867  * For an internet address the host-specific part is just
1868  * the 32 bit IP address and this part of the mask is set
1869  * to all-ones. The port number part of the mask is zeroes.
1870  */
1871 static int
1872 set_addrmask(int fd, struct netconfig *nconf, struct netbuf *mask)
1873 {
1874 	struct t_info info;
1875 
1876 	/*
1877 	 * Find the size of the address we need to mask.
1878 	 */
1879 	if (t_getinfo(fd, &info) < 0) {
1880 		t_error("t_getinfo");
1881 		return (-1);
1882 	}
1883 	mask->len = mask->maxlen = info.addr;
1884 	if (info.addr <= 0) {
1885 		syslog(LOG_ERR, "set_addrmask: address size: %ld",
1886 			info.addr);
1887 		return (-1);
1888 	}
1889 
1890 	mask->buf = (char *)malloc(mask->len);
1891 	if (mask->buf == NULL) {
1892 		syslog(LOG_ERR, "set_addrmask: no memory");
1893 		return (-1);
1894 	}
1895 	(void) memset(mask->buf, 0, mask->len);	/* reset all mask bits */
1896 
1897 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
1898 		/*
1899 		 * Set the mask so that the port is ignored.
1900 		 */
1901 		/* LINTED pointer alignment */
1902 		((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
1903 		    (in_addr_t)~0;
1904 		/* LINTED pointer alignment */
1905 		((struct sockaddr_in *)mask->buf)->sin_family = (sa_family_t)~0;
1906 	}
1907 #ifdef NC_INET6
1908 	else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
1909 		/* LINTED pointer alignment */
1910 		(void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
1911 		    (uchar_t)~0, sizeof (struct in6_addr));
1912 		/* LINTED pointer alignment */
1913 		((struct sockaddr_in6 *)mask->buf)->sin6_family =
1914 		    (sa_family_t)~0;
1915 	}
1916 #endif
1917 	else {
1918 		/*
1919 		 * Set all mask bits.
1920 		 */
1921 		(void) memset(mask->buf, (uchar_t)~0, mask->len);
1922 	}
1923 	return (0);
1924 }
1925 
1926 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
1927 
1928 static int
1929 sndrsvcpool(int maxservers)
1930 {
1931 	struct svcpool_args npa;
1932 
1933 	npa.id = RDC_SVCPOOL_ID;
1934 	npa.maxthreads = maxservers;
1935 	npa.redline = 0;
1936 	npa.qsize = 0;
1937 	npa.timeout = 0;
1938 	npa.stksize = 0;
1939 	npa.max_same_xprt = 0;
1940 	return (sndrsys(RDC_POOL_CREATE, &npa));
1941 }
1942 
1943 
1944 /*
1945  * The following stolen from cmd/fs.d/nfs/lib/thrpool.c
1946  */
1947 
1948 #include <thread.h>
1949 
1950 /*
1951  * Thread to call into the kernel and do work on behalf of SNDR/ncall-ip.
1952  */
1953 static void *
1954 svcstart(void *arg)
1955 {
1956 	int id = (int)arg;
1957 	int err;
1958 
1959 	while ((err = sndrsys(RDC_POOL_RUN, &id)) != 0) {
1960 		/*
1961 		 * Interrupted by a signal while in the kernel.
1962 		 * this process is still alive, try again.
1963 		 */
1964 		if (err == EINTR)
1965 			continue;
1966 		else
1967 			break;
1968 	}
1969 
1970 	/*
1971 	 * If we weren't interrupted by a signal, but did
1972 	 * return from the kernel, this thread's work is done,
1973 	 * and it should exit.
1974 	 */
1975 	thr_exit(NULL);
1976 	return (NULL);
1977 }
1978 
1979 /*
1980  * User-space "creator" thread. This thread blocks in the kernel
1981  * until new worker threads need to be created for the service
1982  * pool. On return to userspace, if there is no error, create a
1983  * new thread for the service pool.
1984  */
1985 static void *
1986 svcblock(void *arg)
1987 {
1988 	int id = (int)arg;
1989 
1990 	/* CONSTCOND */
1991 	while (1) {
1992 		thread_t tid;
1993 		int err;
1994 
1995 		/*
1996 		 * Call into the kernel, and hang out there
1997 		 * until a thread needs to be created.
1998 		 */
1999 		if (err = sndrsys(RDC_POOL_WAIT, &id)) {
2000 			if (err == ECANCELED || err == EBUSY)
2001 				/*
2002 				 * If we get back ECANCELED, the service
2003 				 * pool is exiting, and we may as well
2004 				 * clean up this thread. If EBUSY is
2005 				 * returned, there's already a thread
2006 				 * looping on this pool, so we should
2007 				 * give up.
2008 				 */
2009 				break;
2010 			else
2011 				continue;
2012 		}
2013 
2014 		(void) thr_create(NULL, NULL, svcstart, (void *)id,
2015 		    THR_BOUND | THR_DETACHED, &tid);
2016 	}
2017 
2018 	thr_exit(NULL);
2019 	return (NULL);
2020 }
2021 
2022 static int
2023 svcwait(int id)
2024 {
2025 	thread_t tid;
2026 
2027 	/*
2028 	 * Create a bound thread to wait for kernel LWPs that
2029 	 * need to be created.
2030 	 */
2031 	if (thr_create(NULL, NULL, svcblock, (void *)id,
2032 	    THR_BOUND | THR_DETACHED, &tid))
2033 		return (1);
2034 
2035 	return (0);
2036 }
2037 #endif /* Solaris 9+ */
2038