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