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