xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*45916cd2Sjpk  * Common Development and Distribution License (the "License").
6*45916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*45916cd2Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * nfs_tbind.c, common part for nfsd and lockd.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <tiuser.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <netconfig.h>
357c478bd9Sstevel@tonic-gate #include <stropts.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <syslog.h>
387c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
397c478bd9Sstevel@tonic-gate #include <sys/time.h>
407c478bd9Sstevel@tonic-gate #include <sys/resource.h>
417c478bd9Sstevel@tonic-gate #include <signal.h>
427c478bd9Sstevel@tonic-gate #include <netdir.h>
437c478bd9Sstevel@tonic-gate #include <unistd.h>
447c478bd9Sstevel@tonic-gate #include <string.h>
457c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
467c478bd9Sstevel@tonic-gate #include <malloc.h>
477c478bd9Sstevel@tonic-gate #include <stdlib.h>
487c478bd9Sstevel@tonic-gate #include "nfs_tbind.h"
497c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
507c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
517c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h>
527c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h>
53*45916cd2Sjpk #include <zone.h>
54*45916cd2Sjpk #include <sys/socket.h>
55*45916cd2Sjpk #include <tsol/label.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Determine valid semantics for most applications.
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate #define	OK_TPI_TYPE(_nconf) \
617c478bd9Sstevel@tonic-gate 	(_nconf->nc_semantics == NC_TPI_CLTS || \
627c478bd9Sstevel@tonic-gate 	_nconf->nc_semantics == NC_TPI_COTS || \
637c478bd9Sstevel@tonic-gate 	_nconf->nc_semantics == NC_TPI_COTS_ORD)
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #define	BE32_TO_U32(a) \
667c478bd9Sstevel@tonic-gate 	((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \
677c478bd9Sstevel@tonic-gate 	(((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \
687c478bd9Sstevel@tonic-gate 	(((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8)  | \
697c478bd9Sstevel@tonic-gate 	((ulong_t)((uchar_t *)a)[3] & 0xFF))
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * Number of elements to add to the poll array on each allocation.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate #define	POLL_ARRAY_INC_SIZE	64
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Number of file descriptors by which the process soft limit may be
787c478bd9Sstevel@tonic-gate  * increased on each call to nofile_increase(0).
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate #define	NOFILE_INC_SIZE	64
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate struct conn_ind {
837c478bd9Sstevel@tonic-gate 	struct conn_ind *conn_next;
847c478bd9Sstevel@tonic-gate 	struct conn_ind *conn_prev;
857c478bd9Sstevel@tonic-gate 	struct t_call   *conn_call;
867c478bd9Sstevel@tonic-gate };
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate struct conn_entry {
897c478bd9Sstevel@tonic-gate 	bool_t			closing;
907c478bd9Sstevel@tonic-gate 	struct netconfig	nc;
917c478bd9Sstevel@tonic-gate };
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * this file contains transport routines common to nfsd and lockd
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate static	int	nofile_increase(int);
977c478bd9Sstevel@tonic-gate static	int	reuseaddr(int);
98*45916cd2Sjpk static	int	recvucred(int);
99*45916cd2Sjpk static  int	anonmlp(int);
1007c478bd9Sstevel@tonic-gate static	void	add_to_poll_list(int, struct netconfig *);
1017c478bd9Sstevel@tonic-gate static	char	*serv_name_to_port_name(char *);
1027c478bd9Sstevel@tonic-gate static	int	bind_to_proto(char *, char *, struct netbuf **,
1037c478bd9Sstevel@tonic-gate 				struct netconfig **);
1047c478bd9Sstevel@tonic-gate static	int	bind_to_provider(char *, char *, struct netbuf **,
1057c478bd9Sstevel@tonic-gate 					struct netconfig **);
1067c478bd9Sstevel@tonic-gate static	void	conn_close_oldest(void);
1077c478bd9Sstevel@tonic-gate static	boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
1087c478bd9Sstevel@tonic-gate static	void	cots_listen_event(int, int);
1097c478bd9Sstevel@tonic-gate static	int	discon_get(int, struct netconfig *, struct conn_ind **);
1107c478bd9Sstevel@tonic-gate static	int	do_poll_clts_action(int, int);
1117c478bd9Sstevel@tonic-gate static	int	do_poll_cots_action(int, int);
1127c478bd9Sstevel@tonic-gate static	void	remove_from_poll_list(int);
1137c478bd9Sstevel@tonic-gate static	int	set_addrmask(int, struct netconfig *, struct netbuf *);
1147c478bd9Sstevel@tonic-gate static	int	is_listen_fd_index(int);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static	struct pollfd *poll_array;
1177c478bd9Sstevel@tonic-gate static	struct conn_entry *conn_polled;
1187c478bd9Sstevel@tonic-gate static	int	num_conns;		/* Current number of connections */
1197c478bd9Sstevel@tonic-gate int		(*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
1207c478bd9Sstevel@tonic-gate 		struct netbuf *);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate  * Called to create and prepare a transport descriptor for in-kernel
1247c478bd9Sstevel@tonic-gate  * RPC service.
1257c478bd9Sstevel@tonic-gate  * Returns -1 on failure and a valid descriptor on success.
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate int
1287c478bd9Sstevel@tonic-gate nfslib_transport_open(struct netconfig *nconf)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate 	int fd;
1317c478bd9Sstevel@tonic-gate 	struct strioctl	strioc;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	if ((nconf == (struct netconfig *)NULL) ||
1347c478bd9Sstevel@tonic-gate 	    (nconf->nc_device == (char *)NULL)) {
1357c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "no netconfig device");
1367c478bd9Sstevel@tonic-gate 		return (-1);
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	/*
1407c478bd9Sstevel@tonic-gate 	 * Open the transport device.
1417c478bd9Sstevel@tonic-gate 	 */
1427c478bd9Sstevel@tonic-gate 	fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
1437c478bd9Sstevel@tonic-gate 	if (fd == -1) {
1447c478bd9Sstevel@tonic-gate 		if (t_errno == TSYSERR && errno == EMFILE &&
1457c478bd9Sstevel@tonic-gate 		    (nofile_increase(0) == 0)) {
1467c478bd9Sstevel@tonic-gate 			/* Try again with a higher NOFILE limit. */
1477c478bd9Sstevel@tonic-gate 			fd = t_open(nconf->nc_device, O_RDWR,
1487c478bd9Sstevel@tonic-gate 					(struct t_info *)NULL);
1497c478bd9Sstevel@tonic-gate 		}
1507c478bd9Sstevel@tonic-gate 		if (fd == -1) {
1517c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "t_open %s failed:  t_errno %d, %m",
1527c478bd9Sstevel@tonic-gate 			    nconf->nc_device, t_errno);
1537c478bd9Sstevel@tonic-gate 			return (-1);
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	/*
1587c478bd9Sstevel@tonic-gate 	 * Pop timod because the RPC module must be as close as possible
1597c478bd9Sstevel@tonic-gate 	 * to the transport.
1607c478bd9Sstevel@tonic-gate 	 */
1617c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_POP, 0) < 0) {
1627c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "I_POP of timod failed: %m");
1637c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
1647c478bd9Sstevel@tonic-gate 		return (-1);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/*
1687c478bd9Sstevel@tonic-gate 	 * Common code for CLTS and COTS transports
1697c478bd9Sstevel@tonic-gate 	 */
1707c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
1717c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
1727c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
1737c478bd9Sstevel@tonic-gate 		return (-1);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	strioc.ic_cmd = RPC_SERVER;
1777c478bd9Sstevel@tonic-gate 	strioc.ic_dp = (char *)0;
1787c478bd9Sstevel@tonic-gate 	strioc.ic_len = 0;
1797c478bd9Sstevel@tonic-gate 	strioc.ic_timout = -1;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/* Tell rpcmod to act like a server stream. */
1827c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &strioc) < 0) {
1837c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m");
1847c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
1857c478bd9Sstevel@tonic-gate 		return (-1);
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	/*
1897c478bd9Sstevel@tonic-gate 	 * Re-push timod so that we will still be doing TLI
1907c478bd9Sstevel@tonic-gate 	 * operations on the descriptor.
1917c478bd9Sstevel@tonic-gate 	 */
1927c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_PUSH, "timod") < 0) {
1937c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "I_PUSH of timod failed: %m");
1947c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
1957c478bd9Sstevel@tonic-gate 		return (-1);
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	return (fd);
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate static int
2027c478bd9Sstevel@tonic-gate nofile_increase(int limit)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	struct rlimit rl;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
2077c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "getrlimit of NOFILE failed: %m");
2087c478bd9Sstevel@tonic-gate 		return (-1);
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	if (limit > 0)
2127c478bd9Sstevel@tonic-gate 		rl.rlim_cur = limit;
2137c478bd9Sstevel@tonic-gate 	else
2147c478bd9Sstevel@tonic-gate 		rl.rlim_cur += NOFILE_INC_SIZE;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (rl.rlim_cur > rl.rlim_max &&
2177c478bd9Sstevel@tonic-gate 	    rl.rlim_max != RLIM_INFINITY)
2187c478bd9Sstevel@tonic-gate 		rl.rlim_max = rl.rlim_cur;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
2217c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m",
2227c478bd9Sstevel@tonic-gate 			rl.rlim_cur);
2237c478bd9Sstevel@tonic-gate 		return (-1);
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate int
2307c478bd9Sstevel@tonic-gate nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
2317c478bd9Sstevel@tonic-gate 	struct nd_hostserv *hs, int backlog)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 	int fd;
2347c478bd9Sstevel@tonic-gate 	struct t_bind  *ntb;
2357c478bd9Sstevel@tonic-gate 	struct t_bind tb;
2367c478bd9Sstevel@tonic-gate 	struct nd_addrlist *addrlist;
2377c478bd9Sstevel@tonic-gate 	struct t_optmgmt req, resp;
2387c478bd9Sstevel@tonic-gate 	struct opthdr *opt;
2397c478bd9Sstevel@tonic-gate 	char reqbuf[128];
2407c478bd9Sstevel@tonic-gate 	bool_t use_any = FALSE;
241*45916cd2Sjpk 	bool_t gzone = TRUE;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if ((fd = nfslib_transport_open(nconf)) == -1) {
2447c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "cannot establish transport service over %s",
2457c478bd9Sstevel@tonic-gate 			nconf->nc_device);
2467c478bd9Sstevel@tonic-gate 		return (-1);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	addrlist = (struct nd_addrlist *)NULL;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	/* nfs4_callback service does not used a fieed port number */
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	if (strcmp(hs->h_serv, "nfs4_callback") == 0) {
2547c478bd9Sstevel@tonic-gate 		tb.addr.maxlen = 0;
2557c478bd9Sstevel@tonic-gate 		tb.addr.len = 0;
2567c478bd9Sstevel@tonic-gate 		tb.addr.buf = 0;
2577c478bd9Sstevel@tonic-gate 		use_any = TRUE;
258*45916cd2Sjpk 		gzone = (getzoneid() == GLOBAL_ZONEID);
2597c478bd9Sstevel@tonic-gate 	} else if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
2627c478bd9Sstevel@tonic-gate 		"Cannot get address for transport %s host %s service %s",
2637c478bd9Sstevel@tonic-gate 			nconf->nc_netid, hs->h_host, hs->h_serv);
2647c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
2657c478bd9Sstevel@tonic-gate 		return (-1);
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (strcmp(nconf->nc_proto, "tcp") == 0) {
2697c478bd9Sstevel@tonic-gate 		/*
2707c478bd9Sstevel@tonic-gate 		 * If we're running over TCP, then set the
2717c478bd9Sstevel@tonic-gate 		 * SO_REUSEADDR option so that we can bind
2727c478bd9Sstevel@tonic-gate 		 * to our preferred address even if previously
2737c478bd9Sstevel@tonic-gate 		 * left connections exist in FIN_WAIT states.
2747c478bd9Sstevel@tonic-gate 		 * This is somewhat bogus, but otherwise you have
2757c478bd9Sstevel@tonic-gate 		 * to wait 2 minutes to restart after killing it.
2767c478bd9Sstevel@tonic-gate 		 */
2777c478bd9Sstevel@tonic-gate 		if (reuseaddr(fd) == -1) {
2787c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
2797c478bd9Sstevel@tonic-gate 			"couldn't set SO_REUSEADDR option on transport");
2807c478bd9Sstevel@tonic-gate 		}
281*45916cd2Sjpk 	} else if (strcmp(nconf->nc_proto, "udp") == 0) {
282*45916cd2Sjpk 		/*
283*45916cd2Sjpk 		 * In order to run MLP on UDP, we need to handle creds.
284*45916cd2Sjpk 		 */
285*45916cd2Sjpk 		if (recvucred(fd) == -1) {
286*45916cd2Sjpk 			syslog(LOG_WARNING,
287*45916cd2Sjpk 			    "couldn't set SO_RECVUCRED option on transport");
288*45916cd2Sjpk 		}
289*45916cd2Sjpk 	}
290*45916cd2Sjpk 
291*45916cd2Sjpk 	/*
292*45916cd2Sjpk 	 * Make non global zone nfs4_callback port MLP
293*45916cd2Sjpk 	 */
294*45916cd2Sjpk 	if (use_any && is_system_labeled() && !gzone) {
295*45916cd2Sjpk 		if (anonmlp(fd) == -1) {
296*45916cd2Sjpk 			/*
297*45916cd2Sjpk 			 * failing to set this option means nfs4_callback
298*45916cd2Sjpk 			 * could fail silently later. So fail it with
299*45916cd2Sjpk 			 * with an error message now.
300*45916cd2Sjpk 			 */
301*45916cd2Sjpk 			syslog(LOG_ERR,
302*45916cd2Sjpk 			    "couldn't set SO_ANON_MLP option on transport");
303*45916cd2Sjpk 			(void) t_close(fd);
304*45916cd2Sjpk 			return (-1);
305*45916cd2Sjpk 		}
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	if (nconf->nc_semantics == NC_TPI_CLTS)
3097c478bd9Sstevel@tonic-gate 		tb.qlen = 0;
3107c478bd9Sstevel@tonic-gate 	else
3117c478bd9Sstevel@tonic-gate 		tb.qlen = backlog;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
3147c478bd9Sstevel@tonic-gate 	ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
3157c478bd9Sstevel@tonic-gate 	if (ntb == (struct t_bind *)NULL) {
3167c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "t_alloc failed:  t_errno %d, %m", t_errno);
3177c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
3187c478bd9Sstevel@tonic-gate 		netdir_free((void *)addrlist, ND_ADDRLIST);
3197c478bd9Sstevel@tonic-gate 		return (-1);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/*
3237c478bd9Sstevel@tonic-gate 	 * XXX - what about the space tb->addr.buf points to? This should
3247c478bd9Sstevel@tonic-gate 	 * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,)
3257c478bd9Sstevel@tonic-gate 	 * should't be called with T_ALL.
3267c478bd9Sstevel@tonic-gate 	 */
3277c478bd9Sstevel@tonic-gate 	if (addrlist)
3287c478bd9Sstevel@tonic-gate 		tb.addr = *(addrlist->n_addrs);		/* structure copy */
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (t_bind(fd, &tb, ntb) == -1) {
3317c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "t_bind failed:  t_errno %d, %m", t_errno);
3327c478bd9Sstevel@tonic-gate 		(void) t_free((char *)ntb, T_BIND);
3337c478bd9Sstevel@tonic-gate 		netdir_free((void *)addrlist, ND_ADDRLIST);
3347c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
3357c478bd9Sstevel@tonic-gate 		return (-1);
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	/* make sure we bound to the right address */
3397c478bd9Sstevel@tonic-gate 	if (use_any == FALSE &&
3407c478bd9Sstevel@tonic-gate 	    (tb.addr.len != ntb->addr.len ||
3417c478bd9Sstevel@tonic-gate 	    memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) {
3427c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "t_bind to wrong address");
3437c478bd9Sstevel@tonic-gate 		(void) t_free((char *)ntb, T_BIND);
3447c478bd9Sstevel@tonic-gate 		netdir_free((void *)addrlist, ND_ADDRLIST);
3457c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
3467c478bd9Sstevel@tonic-gate 		return (-1);
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/*
3507c478bd9Sstevel@tonic-gate 	 * Call nfs4svc_setport so that the kernel can be
3517c478bd9Sstevel@tonic-gate 	 * informed what port number the daemon is listing
3527c478bd9Sstevel@tonic-gate 	 * for incoming connection requests.
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if ((nconf->nc_semantics == NC_TPI_COTS ||
3567c478bd9Sstevel@tonic-gate 	    nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL)
3577c478bd9Sstevel@tonic-gate 		(*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	*addr = &ntb->addr;
3607c478bd9Sstevel@tonic-gate 	netdir_free((void *)addrlist, ND_ADDRLIST);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (strcmp(nconf->nc_proto, "tcp") == 0) {
3637c478bd9Sstevel@tonic-gate 		/*
3647c478bd9Sstevel@tonic-gate 		 * Disable the Nagle algorithm on TCP connections.
3657c478bd9Sstevel@tonic-gate 		 * Connections accepted from this listener will
3667c478bd9Sstevel@tonic-gate 		 * inherit the listener options.
3677c478bd9Sstevel@tonic-gate 		 */
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
3707c478bd9Sstevel@tonic-gate 		opt = (struct opthdr *)reqbuf;
3717c478bd9Sstevel@tonic-gate 		opt->level = IPPROTO_TCP;
3727c478bd9Sstevel@tonic-gate 		opt->name = TCP_NODELAY;
3737c478bd9Sstevel@tonic-gate 		opt->len = sizeof (int);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
3767c478bd9Sstevel@tonic-gate 		*(int *)((char *)opt + sizeof (*opt)) = 1;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		req.flags = T_NEGOTIATE;
3797c478bd9Sstevel@tonic-gate 		req.opt.len = sizeof (*opt) + opt->len;
3807c478bd9Sstevel@tonic-gate 		req.opt.buf = (char *)opt;
3817c478bd9Sstevel@tonic-gate 		resp.flags = 0;
3827c478bd9Sstevel@tonic-gate 		resp.opt.buf = reqbuf;
3837c478bd9Sstevel@tonic-gate 		resp.opt.maxlen = sizeof (reqbuf);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		if (t_optmgmt(fd, &req, &resp) < 0 ||
3867c478bd9Sstevel@tonic-gate 				resp.flags != T_SUCCESS) {
3877c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
3887c478bd9Sstevel@tonic-gate 	"couldn't set NODELAY option for proto %s: t_errno = %d, %m",
3897c478bd9Sstevel@tonic-gate 				nconf->nc_proto, t_errno);
3907c478bd9Sstevel@tonic-gate 		}
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	return (fd);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate static int
397*45916cd2Sjpk setopt(int fd, int level, int name, int value)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	struct t_optmgmt req, resp;
400*45916cd2Sjpk 	struct {
401*45916cd2Sjpk 		struct opthdr opt;
402*45916cd2Sjpk 		int value;
403*45916cd2Sjpk 	} reqbuf;
4047c478bd9Sstevel@tonic-gate 
405*45916cd2Sjpk 	reqbuf.opt.level = level;
406*45916cd2Sjpk 	reqbuf.opt.name = name;
407*45916cd2Sjpk 	reqbuf.opt.len = sizeof (int);
4087c478bd9Sstevel@tonic-gate 
409*45916cd2Sjpk 	reqbuf.value = value;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	req.flags = T_NEGOTIATE;
412*45916cd2Sjpk 	req.opt.len = sizeof (reqbuf);
413*45916cd2Sjpk 	req.opt.buf = (char *)&reqbuf;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	resp.flags = 0;
416*45916cd2Sjpk 	resp.opt.buf = (char *)&reqbuf;
4177c478bd9Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
4207c478bd9Sstevel@tonic-gate 		t_error("t_optmgmt");
4217c478bd9Sstevel@tonic-gate 		return (-1);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 	return (0);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
426*45916cd2Sjpk static int
427*45916cd2Sjpk reuseaddr(int fd)
428*45916cd2Sjpk {
429*45916cd2Sjpk 	return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1));
430*45916cd2Sjpk }
431*45916cd2Sjpk 
432*45916cd2Sjpk static int
433*45916cd2Sjpk recvucred(int fd)
434*45916cd2Sjpk {
435*45916cd2Sjpk 	return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1));
436*45916cd2Sjpk }
437*45916cd2Sjpk 
438*45916cd2Sjpk static int
439*45916cd2Sjpk anonmlp(int fd)
440*45916cd2Sjpk {
441*45916cd2Sjpk 	return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1));
442*45916cd2Sjpk }
443*45916cd2Sjpk 
4447c478bd9Sstevel@tonic-gate void
4457c478bd9Sstevel@tonic-gate nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate 	int error;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/*
4507c478bd9Sstevel@tonic-gate 	 * Save the error code across syslog(), just in case syslog()
4517c478bd9Sstevel@tonic-gate 	 * gets its own error and, therefore, overwrites errno.
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	error = errno;
4547c478bd9Sstevel@tonic-gate 	if (t_errno == TSYSERR) {
4557c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
4567c478bd9Sstevel@tonic-gate 			tli_name, fd, nconf->nc_proto);
4577c478bd9Sstevel@tonic-gate 	} else {
4587c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
4597c478bd9Sstevel@tonic-gate 			"%s(file descriptor %d/transport %s) TLI error %d",
4607c478bd9Sstevel@tonic-gate 			tli_name, fd, nconf->nc_proto, t_errno);
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 	errno = error;
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate /*
4667c478bd9Sstevel@tonic-gate  * Called to set up service over a particular transport.
4677c478bd9Sstevel@tonic-gate  */
4687c478bd9Sstevel@tonic-gate void
4697c478bd9Sstevel@tonic-gate do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
4707c478bd9Sstevel@tonic-gate 	int (*svc)(int, struct netbuf, struct netconfig *))
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	register int sock;
4737c478bd9Sstevel@tonic-gate 	struct protob *protobp;
4747c478bd9Sstevel@tonic-gate 	struct netbuf *retaddr;
4757c478bd9Sstevel@tonic-gate 	struct netconfig *retnconf;
4767c478bd9Sstevel@tonic-gate 	struct netbuf addrmask;
4777c478bd9Sstevel@tonic-gate 	int vers;
4787c478bd9Sstevel@tonic-gate 	int err;
4797c478bd9Sstevel@tonic-gate 	int l;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (provider)
4827c478bd9Sstevel@tonic-gate 		sock = bind_to_provider(provider, protobp0->serv, &retaddr,
4837c478bd9Sstevel@tonic-gate 					&retnconf);
4847c478bd9Sstevel@tonic-gate 	else
4857c478bd9Sstevel@tonic-gate 		sock = bind_to_proto(proto, protobp0->serv, &retaddr,
4867c478bd9Sstevel@tonic-gate 					&retnconf);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (sock == -1) {
4897c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
4907c478bd9Sstevel@tonic-gate 	"Cannot establish %s service over %s: transport setup problem.",
4917c478bd9Sstevel@tonic-gate 			protobp0->serv, provider ? provider : proto);
4927c478bd9Sstevel@tonic-gate 		return;
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	if (set_addrmask(sock, retnconf, &addrmask) < 0) {
4967c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
4977c478bd9Sstevel@tonic-gate 		    "Cannot set address mask for %s", retnconf->nc_netid);
4987c478bd9Sstevel@tonic-gate 		return;
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/*
5027c478bd9Sstevel@tonic-gate 	 * Register all versions of the programs in the protocol block list.
5037c478bd9Sstevel@tonic-gate 	 */
5047c478bd9Sstevel@tonic-gate 	l = strlen(NC_UDP);
5057c478bd9Sstevel@tonic-gate 	for (protobp = protobp0; protobp; protobp = protobp->next) {
5067c478bd9Sstevel@tonic-gate 		for (vers = protobp->versmin; vers <= protobp->versmax;
5077c478bd9Sstevel@tonic-gate 			vers++) {
5087c478bd9Sstevel@tonic-gate 			if ((protobp->program == NFS_PROGRAM ||
5097c478bd9Sstevel@tonic-gate 				protobp->program == NFS_ACL_PROGRAM) &&
5107c478bd9Sstevel@tonic-gate 				vers == NFS_V4 &&
5117c478bd9Sstevel@tonic-gate 				strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0)
5127c478bd9Sstevel@tonic-gate 				continue;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 			(void) rpcb_unset(protobp->program, vers, retnconf);
5157c478bd9Sstevel@tonic-gate 			(void) rpcb_set(protobp->program, vers, retnconf,
5167c478bd9Sstevel@tonic-gate 					retaddr);
5177c478bd9Sstevel@tonic-gate 		}
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (retnconf->nc_semantics == NC_TPI_CLTS) {
5217c478bd9Sstevel@tonic-gate 		/* Don't drop core if supporting module(s) aren't loaded. */
5227c478bd9Sstevel@tonic-gate 		(void) signal(SIGSYS, SIG_IGN);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		/*
5257c478bd9Sstevel@tonic-gate 		 * svc() doesn't block, it returns success or failure.
5267c478bd9Sstevel@tonic-gate 		 */
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		if (svc == NULL && Mysvc4 != NULL)
5297c478bd9Sstevel@tonic-gate 			err = (*Mysvc4)(sock, &addrmask, retnconf,
5307c478bd9Sstevel@tonic-gate 					NFS4_SETPORT|NFS4_KRPC_START, retaddr);
5317c478bd9Sstevel@tonic-gate 		else
5327c478bd9Sstevel@tonic-gate 			err = (*svc)(sock, addrmask, retnconf);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 		if (err < 0) {
5357c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
5367c478bd9Sstevel@tonic-gate 				"Cannot establish %s service over <file desc."
5377c478bd9Sstevel@tonic-gate 				" %d, protocol %s> : %m. Exiting",
5387c478bd9Sstevel@tonic-gate 				protobp0->serv, sock, retnconf->nc_proto);
5397c478bd9Sstevel@tonic-gate 			exit(1);
5407c478bd9Sstevel@tonic-gate 		}
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	/*
5447c478bd9Sstevel@tonic-gate 	 * We successfully set up the server over this transport.
5457c478bd9Sstevel@tonic-gate 	 * Add this descriptor to the one being polled on.
5467c478bd9Sstevel@tonic-gate 	 */
5477c478bd9Sstevel@tonic-gate 	add_to_poll_list(sock, retnconf);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate /*
5507c478bd9Sstevel@tonic-gate  * Set up the NFS service over all the available transports.
5517c478bd9Sstevel@tonic-gate  * Returns -1 for failure, 0 for success.
5527c478bd9Sstevel@tonic-gate  */
5537c478bd9Sstevel@tonic-gate int
5547c478bd9Sstevel@tonic-gate do_all(struct protob *protobp,
5557c478bd9Sstevel@tonic-gate 	int (*svc)(int, struct netbuf, struct netconfig *))
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
5587c478bd9Sstevel@tonic-gate 	NCONF_HANDLE *nc;
5597c478bd9Sstevel@tonic-gate 	int l;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
5627c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "setnetconfig failed: %m");
5637c478bd9Sstevel@tonic-gate 		return (-1);
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 	l = strlen(NC_UDP);
5667c478bd9Sstevel@tonic-gate 	while (nconf = getnetconfig(nc)) {
5677c478bd9Sstevel@tonic-gate 		if ((nconf->nc_flag & NC_VISIBLE) &&
5687c478bd9Sstevel@tonic-gate 		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
5697c478bd9Sstevel@tonic-gate 		    OK_TPI_TYPE(nconf) &&
5707c478bd9Sstevel@tonic-gate 		    (protobp->program != NFS4_CALLBACK ||
5717c478bd9Sstevel@tonic-gate 		    strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
5727c478bd9Sstevel@tonic-gate 			do_one(nconf->nc_device, nconf->nc_proto,
5737c478bd9Sstevel@tonic-gate 				protobp, svc);
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 	(void) endnetconfig(nc);
5767c478bd9Sstevel@tonic-gate 	return (0);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  * poll on the open transport descriptors for events and errors.
5817c478bd9Sstevel@tonic-gate  */
5827c478bd9Sstevel@tonic-gate void
5837c478bd9Sstevel@tonic-gate poll_for_action(void)
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	int nfds;
5867c478bd9Sstevel@tonic-gate 	int i;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	/*
5897c478bd9Sstevel@tonic-gate 	 * Keep polling until all transports have been closed. When this
5907c478bd9Sstevel@tonic-gate 	 * happens, we return.
5917c478bd9Sstevel@tonic-gate 	 */
5927c478bd9Sstevel@tonic-gate 	while ((int)num_fds > 0) {
5937c478bd9Sstevel@tonic-gate 		nfds = poll(poll_array, num_fds, INFTIM);
5947c478bd9Sstevel@tonic-gate 		switch (nfds) {
5957c478bd9Sstevel@tonic-gate 		case 0:
5967c478bd9Sstevel@tonic-gate 			continue;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		case -1:
5997c478bd9Sstevel@tonic-gate 			/*
6007c478bd9Sstevel@tonic-gate 			 * Some errors from poll could be
6017c478bd9Sstevel@tonic-gate 			 * due to temporary conditions, and we try to
6027c478bd9Sstevel@tonic-gate 			 * be robust in the face of them. Other
6037c478bd9Sstevel@tonic-gate 			 * errors (should never happen in theory)
6047c478bd9Sstevel@tonic-gate 			 * are fatal (eg. EINVAL, EFAULT).
6057c478bd9Sstevel@tonic-gate 			 */
6067c478bd9Sstevel@tonic-gate 			switch (errno) {
6077c478bd9Sstevel@tonic-gate 			case EINTR:
6087c478bd9Sstevel@tonic-gate 			    continue;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 			case EAGAIN:
6117c478bd9Sstevel@tonic-gate 			case ENOMEM:
6127c478bd9Sstevel@tonic-gate 				(void) sleep(10);
6137c478bd9Sstevel@tonic-gate 				continue;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 			default:
6167c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR,
6177c478bd9Sstevel@tonic-gate 						"poll failed: %m. Exiting");
6187c478bd9Sstevel@tonic-gate 				exit(1);
6197c478bd9Sstevel@tonic-gate 			}
6207c478bd9Sstevel@tonic-gate 		default:
6217c478bd9Sstevel@tonic-gate 			break;
6227c478bd9Sstevel@tonic-gate 		}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 		/*
6257c478bd9Sstevel@tonic-gate 		 * Go through the poll list looking for events.
6267c478bd9Sstevel@tonic-gate 		 */
6277c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_fds && nfds > 0; i++) {
6287c478bd9Sstevel@tonic-gate 			if (poll_array[i].revents) {
6297c478bd9Sstevel@tonic-gate 				nfds--;
6307c478bd9Sstevel@tonic-gate 				/*
6317c478bd9Sstevel@tonic-gate 				 * We have a message, so try to read it.
6327c478bd9Sstevel@tonic-gate 				 * Record the error return in errno,
6337c478bd9Sstevel@tonic-gate 				 * so that syslog(LOG_ERR, "...%m")
6347c478bd9Sstevel@tonic-gate 				 * dumps the corresponding error string.
6357c478bd9Sstevel@tonic-gate 				 */
6367c478bd9Sstevel@tonic-gate 				if (conn_polled[i].nc.nc_semantics ==
6377c478bd9Sstevel@tonic-gate 				    NC_TPI_CLTS) {
6387c478bd9Sstevel@tonic-gate 					errno = do_poll_clts_action(
6397c478bd9Sstevel@tonic-gate 							poll_array[i].fd, i);
6407c478bd9Sstevel@tonic-gate 				} else {
6417c478bd9Sstevel@tonic-gate 					errno = do_poll_cots_action(
6427c478bd9Sstevel@tonic-gate 							poll_array[i].fd, i);
6437c478bd9Sstevel@tonic-gate 				}
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 				if (errno == 0)
6467c478bd9Sstevel@tonic-gate 					continue;
6477c478bd9Sstevel@tonic-gate 				/*
6487c478bd9Sstevel@tonic-gate 				 * Most returned error codes mean that there is
6497c478bd9Sstevel@tonic-gate 				 * fatal condition which we can only deal with
6507c478bd9Sstevel@tonic-gate 				 * by closing the transport.
6517c478bd9Sstevel@tonic-gate 				 */
6527c478bd9Sstevel@tonic-gate 				if (errno != EAGAIN && errno != ENOMEM) {
6537c478bd9Sstevel@tonic-gate 					(void) syslog(LOG_ERR,
6547c478bd9Sstevel@tonic-gate 		"Error (%m) reading descriptor %d/transport %s. Closing it.",
6557c478bd9Sstevel@tonic-gate 						poll_array[i].fd,
6567c478bd9Sstevel@tonic-gate 						conn_polled[i].nc.nc_proto);
6577c478bd9Sstevel@tonic-gate 					(void) t_close(poll_array[i].fd);
6587c478bd9Sstevel@tonic-gate 					remove_from_poll_list(poll_array[i].fd);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 				} else if (errno == ENOMEM)
6617c478bd9Sstevel@tonic-gate 					(void) sleep(5);
6627c478bd9Sstevel@tonic-gate 			}
6637c478bd9Sstevel@tonic-gate 		}
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	(void) syslog(LOG_ERR,
6677c478bd9Sstevel@tonic-gate 		"All transports have been closed with errors. Exiting.");
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  * Allocate poll/transport array entries for this descriptor.
6727c478bd9Sstevel@tonic-gate  */
6737c478bd9Sstevel@tonic-gate static void
6747c478bd9Sstevel@tonic-gate add_to_poll_list(int fd, struct netconfig *nconf)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	static int poll_array_size = 0;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	/*
6797c478bd9Sstevel@tonic-gate 	 * If the arrays are full, allocate new ones.
6807c478bd9Sstevel@tonic-gate 	 */
6817c478bd9Sstevel@tonic-gate 	if (num_fds == poll_array_size) {
6827c478bd9Sstevel@tonic-gate 		struct pollfd *tpa;
6837c478bd9Sstevel@tonic-gate 		struct conn_entry *tnp;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 		if (poll_array_size != 0) {
6867c478bd9Sstevel@tonic-gate 			tpa = poll_array;
6877c478bd9Sstevel@tonic-gate 			tnp = conn_polled;
6887c478bd9Sstevel@tonic-gate 		} else
6897c478bd9Sstevel@tonic-gate 			tpa = (struct pollfd *)0;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		poll_array_size += POLL_ARRAY_INC_SIZE;
6927c478bd9Sstevel@tonic-gate 		/*
6937c478bd9Sstevel@tonic-gate 		 * Allocate new arrays.
6947c478bd9Sstevel@tonic-gate 		 */
6957c478bd9Sstevel@tonic-gate 		poll_array = (struct pollfd *)
6967c478bd9Sstevel@tonic-gate 		    malloc(poll_array_size * sizeof (struct pollfd) + 256);
6977c478bd9Sstevel@tonic-gate 		conn_polled = (struct conn_entry *)
6987c478bd9Sstevel@tonic-gate 		    malloc(poll_array_size * sizeof (struct conn_entry) + 256);
6997c478bd9Sstevel@tonic-gate 		if (poll_array == (struct pollfd *)NULL ||
7007c478bd9Sstevel@tonic-gate 		    conn_polled == (struct conn_entry *)NULL) {
7017c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "malloc failed for poll array");
7027c478bd9Sstevel@tonic-gate 			exit(1);
7037c478bd9Sstevel@tonic-gate 		}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 		/*
7067c478bd9Sstevel@tonic-gate 		 * Copy the data of the old ones into new arrays, and
7077c478bd9Sstevel@tonic-gate 		 * free the old ones.
7087c478bd9Sstevel@tonic-gate 		 */
7097c478bd9Sstevel@tonic-gate 		if (tpa) {
7107c478bd9Sstevel@tonic-gate 			(void) memcpy((void *)poll_array, (void *)tpa,
7117c478bd9Sstevel@tonic-gate 				num_fds * sizeof (struct pollfd));
7127c478bd9Sstevel@tonic-gate 			(void) memcpy((void *)conn_polled, (void *)tnp,
7137c478bd9Sstevel@tonic-gate 				num_fds * sizeof (struct conn_entry));
7147c478bd9Sstevel@tonic-gate 			free((void *)tpa);
7157c478bd9Sstevel@tonic-gate 			free((void *)tnp);
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	/*
7207c478bd9Sstevel@tonic-gate 	 * Set the descriptor and event list. All possible events are
7217c478bd9Sstevel@tonic-gate 	 * polled for.
7227c478bd9Sstevel@tonic-gate 	 */
7237c478bd9Sstevel@tonic-gate 	poll_array[num_fds].fd = fd;
7247c478bd9Sstevel@tonic-gate 	poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	/*
7277c478bd9Sstevel@tonic-gate 	 * Copy the transport data over too.
7287c478bd9Sstevel@tonic-gate 	 */
7297c478bd9Sstevel@tonic-gate 	conn_polled[num_fds].nc = *nconf;
7307c478bd9Sstevel@tonic-gate 	conn_polled[num_fds].closing = 0;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	/*
7337c478bd9Sstevel@tonic-gate 	 * Set the descriptor to non-blocking. Avoids a race
7347c478bd9Sstevel@tonic-gate 	 * between data arriving on the stream and then having it
7357c478bd9Sstevel@tonic-gate 	 * flushed before we can read it.
7367c478bd9Sstevel@tonic-gate 	 */
7377c478bd9Sstevel@tonic-gate 	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
7387c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
7397c478bd9Sstevel@tonic-gate 	"fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting",
7407c478bd9Sstevel@tonic-gate 			num_fds, nconf->nc_proto);
7417c478bd9Sstevel@tonic-gate 		exit(1);
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	/*
7457c478bd9Sstevel@tonic-gate 	 * Count this descriptor.
7467c478bd9Sstevel@tonic-gate 	 */
7477c478bd9Sstevel@tonic-gate 	++num_fds;
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate static void
7517c478bd9Sstevel@tonic-gate remove_from_poll_list(int fd)
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate 	int i;
7547c478bd9Sstevel@tonic-gate 	int num_to_copy;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_fds; i++) {
7577c478bd9Sstevel@tonic-gate 		if (poll_array[i].fd == fd) {
7587c478bd9Sstevel@tonic-gate 			--num_fds;
7597c478bd9Sstevel@tonic-gate 			num_to_copy = num_fds - i;
7607c478bd9Sstevel@tonic-gate 			(void) memcpy((void *)&poll_array[i],
7617c478bd9Sstevel@tonic-gate 				(void *)&poll_array[i+1],
7627c478bd9Sstevel@tonic-gate 				num_to_copy * sizeof (struct pollfd));
7637c478bd9Sstevel@tonic-gate 			(void) memset((void *)&poll_array[num_fds], 0,
7647c478bd9Sstevel@tonic-gate 				sizeof (struct pollfd));
7657c478bd9Sstevel@tonic-gate 			(void) memcpy((void *)&conn_polled[i],
7667c478bd9Sstevel@tonic-gate 				(void *)&conn_polled[i+1],
7677c478bd9Sstevel@tonic-gate 				num_to_copy * sizeof (struct conn_entry));
7687c478bd9Sstevel@tonic-gate 			(void) memset((void *)&conn_polled[num_fds], 0,
7697c478bd9Sstevel@tonic-gate 				sizeof (struct conn_entry));
7707c478bd9Sstevel@tonic-gate 			return;
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate  * Called to read and interpret the event on a connectionless descriptor.
7797c478bd9Sstevel@tonic-gate  * Returns 0 if successful, or a UNIX error code if failure.
7807c478bd9Sstevel@tonic-gate  */
7817c478bd9Sstevel@tonic-gate static int
7827c478bd9Sstevel@tonic-gate do_poll_clts_action(int fd, int conn_index)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	int error;
7857c478bd9Sstevel@tonic-gate 	int ret;
7867c478bd9Sstevel@tonic-gate 	int flags;
7877c478bd9Sstevel@tonic-gate 	struct netconfig *nconf = &conn_polled[conn_index].nc;
7887c478bd9Sstevel@tonic-gate 	static struct t_unitdata *unitdata = NULL;
7897c478bd9Sstevel@tonic-gate 	static struct t_uderr *uderr = NULL;
7907c478bd9Sstevel@tonic-gate 	static int oldfd = -1;
7917c478bd9Sstevel@tonic-gate 	struct nd_hostservlist *host = NULL;
7927c478bd9Sstevel@tonic-gate 	struct strbuf ctl[1], data[1];
7937c478bd9Sstevel@tonic-gate 	/*
7947c478bd9Sstevel@tonic-gate 	 * We just need to have some space to consume the
7957c478bd9Sstevel@tonic-gate 	 * message in the event we can't use the TLI interface to do the
7967c478bd9Sstevel@tonic-gate 	 * job.
7977c478bd9Sstevel@tonic-gate 	 *
7987c478bd9Sstevel@tonic-gate 	 * We flush the message using getmsg(). For the control part
7997c478bd9Sstevel@tonic-gate 	 * we allocate enough for any TPI header plus 32 bytes for address
8007c478bd9Sstevel@tonic-gate 	 * and options. For the data part, there is nothing magic about
8017c478bd9Sstevel@tonic-gate 	 * the size of the array, but 256 bytes is probably better than
8027c478bd9Sstevel@tonic-gate 	 * 1 byte, and we don't expect any data portion anyway.
8037c478bd9Sstevel@tonic-gate 	 *
8047c478bd9Sstevel@tonic-gate 	 * If the array sizes are too small, we handle this because getmsg()
8057c478bd9Sstevel@tonic-gate 	 * (called to consume the message) will return MOREDATA|MORECTL.
8067c478bd9Sstevel@tonic-gate 	 * Thus we just call getmsg() until it's read the message.
8077c478bd9Sstevel@tonic-gate 	 */
8087c478bd9Sstevel@tonic-gate 	char ctlbuf[sizeof (union T_primitives) + 32];
8097c478bd9Sstevel@tonic-gate 	char databuf[256];
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	/*
8127c478bd9Sstevel@tonic-gate 	 * If this is the same descriptor as the last time
8137c478bd9Sstevel@tonic-gate 	 * do_poll_clts_action was called, we can save some
8147c478bd9Sstevel@tonic-gate 	 * de-allocation and allocation.
8157c478bd9Sstevel@tonic-gate 	 */
8167c478bd9Sstevel@tonic-gate 	if (oldfd != fd) {
8177c478bd9Sstevel@tonic-gate 		oldfd = fd;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 		if (unitdata) {
8207c478bd9Sstevel@tonic-gate 			(void) t_free((char *)unitdata, T_UNITDATA);
8217c478bd9Sstevel@tonic-gate 			unitdata = NULL;
8227c478bd9Sstevel@tonic-gate 		}
8237c478bd9Sstevel@tonic-gate 		if (uderr) {
8247c478bd9Sstevel@tonic-gate 			(void) t_free((char *)uderr, T_UDERROR);
8257c478bd9Sstevel@tonic-gate 			uderr = NULL;
8267c478bd9Sstevel@tonic-gate 		}
8277c478bd9Sstevel@tonic-gate 	}
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	/*
8307c478bd9Sstevel@tonic-gate 	 * Allocate a unitdata structure for receiving the event.
8317c478bd9Sstevel@tonic-gate 	 */
8327c478bd9Sstevel@tonic-gate 	if (unitdata == NULL) {
8337c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
8347c478bd9Sstevel@tonic-gate 		unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
8357c478bd9Sstevel@tonic-gate 		if (unitdata == NULL) {
8367c478bd9Sstevel@tonic-gate 			if (t_errno == TSYSERR) {
8377c478bd9Sstevel@tonic-gate 				/*
8387c478bd9Sstevel@tonic-gate 				 * Save the error code across
8397c478bd9Sstevel@tonic-gate 				 * syslog(), just in case
8407c478bd9Sstevel@tonic-gate 				 * syslog() gets its own error
8417c478bd9Sstevel@tonic-gate 				 * and therefore overwrites errno.
8427c478bd9Sstevel@tonic-gate 				 */
8437c478bd9Sstevel@tonic-gate 				error = errno;
8447c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR,
8457c478bd9Sstevel@tonic-gate 	"t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
8467c478bd9Sstevel@tonic-gate 					fd, nconf->nc_proto);
8477c478bd9Sstevel@tonic-gate 				return (error);
8487c478bd9Sstevel@tonic-gate 			}
8497c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
8507c478bd9Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
8517c478bd9Sstevel@tonic-gate 					fd, nconf->nc_proto, t_errno);
8527c478bd9Sstevel@tonic-gate 			goto flush_it;
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate try_again:
8577c478bd9Sstevel@tonic-gate 	flags = 0;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	/*
8607c478bd9Sstevel@tonic-gate 	 * The idea is we wait for T_UNITDATA_IND's. Of course,
8617c478bd9Sstevel@tonic-gate 	 * we don't get any, because rpcmod filters them out.
8627c478bd9Sstevel@tonic-gate 	 * However, we need to call t_rcvudata() to let TLI
8637c478bd9Sstevel@tonic-gate 	 * tell us we have a T_UDERROR_IND.
8647c478bd9Sstevel@tonic-gate 	 *
8657c478bd9Sstevel@tonic-gate 	 * algorithm is:
8667c478bd9Sstevel@tonic-gate 	 * 	t_rcvudata(), expecting TLOOK.
8677c478bd9Sstevel@tonic-gate 	 * 	t_look(), expecting T_UDERR.
8687c478bd9Sstevel@tonic-gate 	 * 	t_rcvuderr(), expecting success (0).
8697c478bd9Sstevel@tonic-gate 	 * 	expand destination address into ASCII,
8707c478bd9Sstevel@tonic-gate 	 *	and dump it.
8717c478bd9Sstevel@tonic-gate 	 */
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	ret = t_rcvudata(fd, unitdata, &flags);
8747c478bd9Sstevel@tonic-gate 	if (ret == 0 || t_errno == TBUFOVFLW) {
8757c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_WARNING,
8767c478bd9Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
8777c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto, unitdata->udata.len);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		/*
8807c478bd9Sstevel@tonic-gate 		 * Even though we don't expect any data, in case we do,
8817c478bd9Sstevel@tonic-gate 		 * keep reading until there is no more.
8827c478bd9Sstevel@tonic-gate 		 */
8837c478bd9Sstevel@tonic-gate 		if (flags & T_MORE)
8847c478bd9Sstevel@tonic-gate 			goto try_again;
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 		return (0);
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	switch (t_errno) {
8907c478bd9Sstevel@tonic-gate 	case TNODATA:
8917c478bd9Sstevel@tonic-gate 		return (0);
8927c478bd9Sstevel@tonic-gate 	case TSYSERR:
8937c478bd9Sstevel@tonic-gate 		/*
8947c478bd9Sstevel@tonic-gate 		 * System errors are returned to caller.
8957c478bd9Sstevel@tonic-gate 		 * Save the error code across
8967c478bd9Sstevel@tonic-gate 		 * syslog(), just in case
8977c478bd9Sstevel@tonic-gate 		 * syslog() gets its own error
8987c478bd9Sstevel@tonic-gate 		 * and therefore overwrites errno.
8997c478bd9Sstevel@tonic-gate 		 */
9007c478bd9Sstevel@tonic-gate 		error = errno;
9017c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
9027c478bd9Sstevel@tonic-gate 			"t_rcvudata(file descriptor %d/transport %s) %m",
9037c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto);
9047c478bd9Sstevel@tonic-gate 		return (error);
9057c478bd9Sstevel@tonic-gate 	case TLOOK:
9067c478bd9Sstevel@tonic-gate 		break;
9077c478bd9Sstevel@tonic-gate 	default:
9087c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
9097c478bd9Sstevel@tonic-gate 		"t_rcvudata(file descriptor %d/transport %s) TLI error %d",
9107c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto, t_errno);
9117c478bd9Sstevel@tonic-gate 		goto flush_it;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	ret = t_look(fd);
9157c478bd9Sstevel@tonic-gate 	switch (ret) {
9167c478bd9Sstevel@tonic-gate 	case 0:
9177c478bd9Sstevel@tonic-gate 		return (0);
9187c478bd9Sstevel@tonic-gate 	case -1:
9197c478bd9Sstevel@tonic-gate 		/*
9207c478bd9Sstevel@tonic-gate 		 * System errors are returned to caller.
9217c478bd9Sstevel@tonic-gate 		 */
9227c478bd9Sstevel@tonic-gate 		if (t_errno == TSYSERR) {
9237c478bd9Sstevel@tonic-gate 			/*
9247c478bd9Sstevel@tonic-gate 			 * Save the error code across
9257c478bd9Sstevel@tonic-gate 			 * syslog(), just in case
9267c478bd9Sstevel@tonic-gate 			 * syslog() gets its own error
9277c478bd9Sstevel@tonic-gate 			 * and therefore overwrites errno.
9287c478bd9Sstevel@tonic-gate 			 */
9297c478bd9Sstevel@tonic-gate 			error = errno;
9307c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
9317c478bd9Sstevel@tonic-gate 				"t_look(file descriptor %d/transport %s) %m",
9327c478bd9Sstevel@tonic-gate 				fd, nconf->nc_proto);
9337c478bd9Sstevel@tonic-gate 			return (error);
9347c478bd9Sstevel@tonic-gate 		}
9357c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
9367c478bd9Sstevel@tonic-gate 			"t_look(file descriptor %d/transport %s) TLI error %d",
9377c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto, t_errno);
9387c478bd9Sstevel@tonic-gate 		goto flush_it;
9397c478bd9Sstevel@tonic-gate 	case T_UDERR:
9407c478bd9Sstevel@tonic-gate 		break;
9417c478bd9Sstevel@tonic-gate 	default:
9427c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_WARNING,
9437c478bd9Sstevel@tonic-gate 	"t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
9447c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto, ret, T_UDERR);
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	if (uderr == NULL) {
9487c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
9497c478bd9Sstevel@tonic-gate 		uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
9507c478bd9Sstevel@tonic-gate 		if (uderr == NULL) {
9517c478bd9Sstevel@tonic-gate 			if (t_errno == TSYSERR) {
9527c478bd9Sstevel@tonic-gate 				/*
9537c478bd9Sstevel@tonic-gate 				 * Save the error code across
9547c478bd9Sstevel@tonic-gate 				 * syslog(), just in case
9557c478bd9Sstevel@tonic-gate 				 * syslog() gets its own error
9567c478bd9Sstevel@tonic-gate 				 * and therefore overwrites errno.
9577c478bd9Sstevel@tonic-gate 				 */
9587c478bd9Sstevel@tonic-gate 				error = errno;
9597c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR,
9607c478bd9Sstevel@tonic-gate 	"t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
9617c478bd9Sstevel@tonic-gate 					fd, nconf->nc_proto);
9627c478bd9Sstevel@tonic-gate 				return (error);
9637c478bd9Sstevel@tonic-gate 			}
9647c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
9657c478bd9Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
9667c478bd9Sstevel@tonic-gate 				fd, nconf->nc_proto, t_errno);
9677c478bd9Sstevel@tonic-gate 			goto flush_it;
9687c478bd9Sstevel@tonic-gate 		}
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	ret = t_rcvuderr(fd, uderr);
9727c478bd9Sstevel@tonic-gate 	if (ret == 0) {
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		/*
9757c478bd9Sstevel@tonic-gate 		 * Save the datagram error in errno, so that the
9767c478bd9Sstevel@tonic-gate 		 * %m argument to syslog picks up the error string.
9777c478bd9Sstevel@tonic-gate 		 */
9787c478bd9Sstevel@tonic-gate 		errno = uderr->error;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		/*
9817c478bd9Sstevel@tonic-gate 		 * Log the datagram error, then log the host that
9827c478bd9Sstevel@tonic-gate 		 * probably triggerred. Cannot log both in the
9837c478bd9Sstevel@tonic-gate 		 * same transaction because of packet size limitations
9847c478bd9Sstevel@tonic-gate 		 * in /dev/log.
9857c478bd9Sstevel@tonic-gate 		 */
9867c478bd9Sstevel@tonic-gate 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
9877c478bd9Sstevel@tonic-gate "NFS response over <file descriptor %d/transport %s> generated error: %m",
9887c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto);
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 		/*
9917c478bd9Sstevel@tonic-gate 		 * Try to map the client's address back to a
9927c478bd9Sstevel@tonic-gate 		 * name.
9937c478bd9Sstevel@tonic-gate 		 */
9947c478bd9Sstevel@tonic-gate 		ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
9957c478bd9Sstevel@tonic-gate 		if (ret != -1 && host && host->h_cnt > 0 &&
9967c478bd9Sstevel@tonic-gate 		    host->h_hostservs) {
9977c478bd9Sstevel@tonic-gate 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
9987c478bd9Sstevel@tonic-gate "Bad NFS response was sent to client with host name: %s; service port: %s",
9997c478bd9Sstevel@tonic-gate 				host->h_hostservs->h_host,
10007c478bd9Sstevel@tonic-gate 				host->h_hostservs->h_serv);
10017c478bd9Sstevel@tonic-gate 		} else {
10027c478bd9Sstevel@tonic-gate 			int i, j;
10037c478bd9Sstevel@tonic-gate 			char *buf;
10047c478bd9Sstevel@tonic-gate 			char *hex = "0123456789abcdef";
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 			/*
10077c478bd9Sstevel@tonic-gate 			 * Mapping failed, print the whole thing
10087c478bd9Sstevel@tonic-gate 			 * in ASCII hex.
10097c478bd9Sstevel@tonic-gate 			 */
10107c478bd9Sstevel@tonic-gate 			buf = (char *)malloc(uderr->addr.len * 2 + 1);
10117c478bd9Sstevel@tonic-gate 			for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
10127c478bd9Sstevel@tonic-gate 				buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
10137c478bd9Sstevel@tonic-gate 				buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
10147c478bd9Sstevel@tonic-gate 			}
10157c478bd9Sstevel@tonic-gate 			buf[j] = '\0';
10167c478bd9Sstevel@tonic-gate 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
10177c478bd9Sstevel@tonic-gate 	"Bad NFS response was sent to client with transport address: 0x%s",
10187c478bd9Sstevel@tonic-gate 				buf);
10197c478bd9Sstevel@tonic-gate 			free((void *)buf);
10207c478bd9Sstevel@tonic-gate 		}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 		if (ret == 0 && host != NULL)
10237c478bd9Sstevel@tonic-gate 			netdir_free((void *)host, ND_HOSTSERVLIST);
10247c478bd9Sstevel@tonic-gate 		return (0);
10257c478bd9Sstevel@tonic-gate 	}
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	switch (t_errno) {
10287c478bd9Sstevel@tonic-gate 	case TNOUDERR:
10297c478bd9Sstevel@tonic-gate 		goto flush_it;
10307c478bd9Sstevel@tonic-gate 	case TSYSERR:
10317c478bd9Sstevel@tonic-gate 		/*
10327c478bd9Sstevel@tonic-gate 		 * System errors are returned to caller.
10337c478bd9Sstevel@tonic-gate 		 * Save the error code across
10347c478bd9Sstevel@tonic-gate 		 * syslog(), just in case
10357c478bd9Sstevel@tonic-gate 		 * syslog() gets its own error
10367c478bd9Sstevel@tonic-gate 		 * and therefore overwrites errno.
10377c478bd9Sstevel@tonic-gate 		 */
10387c478bd9Sstevel@tonic-gate 		error = errno;
10397c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
10407c478bd9Sstevel@tonic-gate 			"t_rcvuderr(file descriptor %d/transport %s) %m",
10417c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto);
10427c478bd9Sstevel@tonic-gate 		return (error);
10437c478bd9Sstevel@tonic-gate 	default:
10447c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
10457c478bd9Sstevel@tonic-gate 		"t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
10467c478bd9Sstevel@tonic-gate 			fd, nconf->nc_proto, t_errno);
10477c478bd9Sstevel@tonic-gate 		goto flush_it;
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate flush_it:
10517c478bd9Sstevel@tonic-gate 	/*
10527c478bd9Sstevel@tonic-gate 	 * If we get here, then we could not cope with whatever message
10537c478bd9Sstevel@tonic-gate 	 * we attempted to read, so flush it. If we did read a message,
10547c478bd9Sstevel@tonic-gate 	 * and one isn't present, that is all right, because fd is in
10557c478bd9Sstevel@tonic-gate 	 * nonblocking mode.
10567c478bd9Sstevel@tonic-gate 	 */
10577c478bd9Sstevel@tonic-gate 	(void) syslog(LOG_ERR,
10587c478bd9Sstevel@tonic-gate 	"Flushing one input message from <file descriptor %d/transport %s>",
10597c478bd9Sstevel@tonic-gate 		fd, nconf->nc_proto);
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	/*
10627c478bd9Sstevel@tonic-gate 	 * Read and discard the message. Do this this until there is
10637c478bd9Sstevel@tonic-gate 	 * no more control/data in the message or until we get an error.
10647c478bd9Sstevel@tonic-gate 	 */
10657c478bd9Sstevel@tonic-gate 	do {
10667c478bd9Sstevel@tonic-gate 		ctl->maxlen = sizeof (ctlbuf);
10677c478bd9Sstevel@tonic-gate 		ctl->buf = ctlbuf;
10687c478bd9Sstevel@tonic-gate 		data->maxlen = sizeof (databuf);
10697c478bd9Sstevel@tonic-gate 		data->buf = databuf;
10707c478bd9Sstevel@tonic-gate 		flags = 0;
10717c478bd9Sstevel@tonic-gate 		ret = getmsg(fd, ctl, data, &flags);
10727c478bd9Sstevel@tonic-gate 		if (ret == -1)
10737c478bd9Sstevel@tonic-gate 			return (errno);
10747c478bd9Sstevel@tonic-gate 	} while (ret != 0);
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	return (0);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate static void
10807c478bd9Sstevel@tonic-gate conn_close_oldest(void)
10817c478bd9Sstevel@tonic-gate {
10827c478bd9Sstevel@tonic-gate 	int fd;
10837c478bd9Sstevel@tonic-gate 	int i1;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	/*
10867c478bd9Sstevel@tonic-gate 	 * Find the oldest connection that is not already in the
10877c478bd9Sstevel@tonic-gate 	 * process of shutting down.
10887c478bd9Sstevel@tonic-gate 	 */
10897c478bd9Sstevel@tonic-gate 	for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
10907c478bd9Sstevel@tonic-gate 		if (i1 >= num_fds)
10917c478bd9Sstevel@tonic-gate 			return;
10927c478bd9Sstevel@tonic-gate 		if (conn_polled[i1].closing == 0)
10937c478bd9Sstevel@tonic-gate 			break;
10947c478bd9Sstevel@tonic-gate 	}
10957c478bd9Sstevel@tonic-gate #ifdef DEBUG
10967c478bd9Sstevel@tonic-gate 	printf("too many connections (%d), releasing oldest (%d)\n",
10977c478bd9Sstevel@tonic-gate 		num_conns, poll_array[i1].fd);
10987c478bd9Sstevel@tonic-gate #else
10997c478bd9Sstevel@tonic-gate 	syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
11007c478bd9Sstevel@tonic-gate 		num_conns, poll_array[i1].fd);
11017c478bd9Sstevel@tonic-gate #endif
11027c478bd9Sstevel@tonic-gate 	fd = poll_array[i1].fd;
11037c478bd9Sstevel@tonic-gate 	if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
11047c478bd9Sstevel@tonic-gate 		/*
11057c478bd9Sstevel@tonic-gate 		 * For politeness, send a T_DISCON_REQ to the transport
11067c478bd9Sstevel@tonic-gate 		 * provider.  We close the stream anyway.
11077c478bd9Sstevel@tonic-gate 		 */
11087c478bd9Sstevel@tonic-gate 		(void) t_snddis(fd, (struct t_call *)0);
11097c478bd9Sstevel@tonic-gate 		num_conns--;
11107c478bd9Sstevel@tonic-gate 		remove_from_poll_list(fd);
11117c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
11127c478bd9Sstevel@tonic-gate 	} else {
11137c478bd9Sstevel@tonic-gate 		/*
11147c478bd9Sstevel@tonic-gate 		 * For orderly release, we do not close the stream
11157c478bd9Sstevel@tonic-gate 		 * until the T_ORDREL_IND arrives to complete
11167c478bd9Sstevel@tonic-gate 		 * the handshake.
11177c478bd9Sstevel@tonic-gate 		 */
11187c478bd9Sstevel@tonic-gate 		if (t_sndrel(fd) == 0)
11197c478bd9Sstevel@tonic-gate 			conn_polled[i1].closing = 1;
11207c478bd9Sstevel@tonic-gate 	}
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate static boolean_t
11247c478bd9Sstevel@tonic-gate conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
11257c478bd9Sstevel@tonic-gate {
11267c478bd9Sstevel@tonic-gate 	struct conn_ind	*conn;
11277c478bd9Sstevel@tonic-gate 	struct conn_ind	*next_conn;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	conn = (struct conn_ind *)malloc(sizeof (*conn));
11307c478bd9Sstevel@tonic-gate 	if (conn == NULL) {
11317c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "malloc for listen indication failed");
11327c478bd9Sstevel@tonic-gate 		return (FALSE);
11337c478bd9Sstevel@tonic-gate 	}
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
11367c478bd9Sstevel@tonic-gate 	conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
11377c478bd9Sstevel@tonic-gate 	if (conn->conn_call == NULL) {
11387c478bd9Sstevel@tonic-gate 		free((char *)conn);
11397c478bd9Sstevel@tonic-gate 		nfslib_log_tli_error("t_alloc", fd, nconf);
11407c478bd9Sstevel@tonic-gate 		return (FALSE);
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	if (t_listen(fd, conn->conn_call) == -1) {
11447c478bd9Sstevel@tonic-gate 		nfslib_log_tli_error("t_listen", fd, nconf);
11457c478bd9Sstevel@tonic-gate 		(void) t_free((char *)conn->conn_call, T_CALL);
11467c478bd9Sstevel@tonic-gate 		free((char *)conn);
11477c478bd9Sstevel@tonic-gate 		return (FALSE);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	if (conn->conn_call->udata.len > 0) {
11517c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING,
11527c478bd9Sstevel@tonic-gate 	"rejecting inbound connection(%s) with %d bytes of connect data",
11537c478bd9Sstevel@tonic-gate 			nconf->nc_proto, conn->conn_call->udata.len);
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 		conn->conn_call->udata.len = 0;
11567c478bd9Sstevel@tonic-gate 		(void) t_snddis(fd, conn->conn_call);
11577c478bd9Sstevel@tonic-gate 		(void) t_free((char *)conn->conn_call, T_CALL);
11587c478bd9Sstevel@tonic-gate 		free((char *)conn);
11597c478bd9Sstevel@tonic-gate 		return (FALSE);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	if ((next_conn = *connp) != NULL) {
11637c478bd9Sstevel@tonic-gate 		next_conn->conn_prev->conn_next = conn;
11647c478bd9Sstevel@tonic-gate 		conn->conn_next = next_conn;
11657c478bd9Sstevel@tonic-gate 		conn->conn_prev = next_conn->conn_prev;
11667c478bd9Sstevel@tonic-gate 		next_conn->conn_prev = conn;
11677c478bd9Sstevel@tonic-gate 	} else {
11687c478bd9Sstevel@tonic-gate 		conn->conn_next = conn;
11697c478bd9Sstevel@tonic-gate 		conn->conn_prev = conn;
11707c478bd9Sstevel@tonic-gate 		*connp = conn;
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 	return (TRUE);
11737c478bd9Sstevel@tonic-gate }
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate static int
11767c478bd9Sstevel@tonic-gate discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
11777c478bd9Sstevel@tonic-gate {
11787c478bd9Sstevel@tonic-gate 	struct conn_ind	*conn;
11797c478bd9Sstevel@tonic-gate 	struct t_discon	discon;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	discon.udata.buf = (char *)0;
11827c478bd9Sstevel@tonic-gate 	discon.udata.maxlen = 0;
11837c478bd9Sstevel@tonic-gate 	if (t_rcvdis(fd, &discon) == -1) {
11847c478bd9Sstevel@tonic-gate 		nfslib_log_tli_error("t_rcvdis", fd, nconf);
11857c478bd9Sstevel@tonic-gate 		return (-1);
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	conn = *connp;
11897c478bd9Sstevel@tonic-gate 	if (conn == NULL)
11907c478bd9Sstevel@tonic-gate 		return (0);
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	do {
11937c478bd9Sstevel@tonic-gate 		if (conn->conn_call->sequence == discon.sequence) {
11947c478bd9Sstevel@tonic-gate 			if (conn->conn_next == conn)
11957c478bd9Sstevel@tonic-gate 				*connp = (struct conn_ind *)0;
11967c478bd9Sstevel@tonic-gate 			else {
11977c478bd9Sstevel@tonic-gate 				if (conn == *connp) {
11987c478bd9Sstevel@tonic-gate 					*connp = conn->conn_next;
11997c478bd9Sstevel@tonic-gate 				}
12007c478bd9Sstevel@tonic-gate 				conn->conn_next->conn_prev = conn->conn_prev;
12017c478bd9Sstevel@tonic-gate 				conn->conn_prev->conn_next = conn->conn_next;
12027c478bd9Sstevel@tonic-gate 			}
12037c478bd9Sstevel@tonic-gate 			free((char *)conn);
12047c478bd9Sstevel@tonic-gate 			break;
12057c478bd9Sstevel@tonic-gate 		}
12067c478bd9Sstevel@tonic-gate 		conn = conn->conn_next;
12077c478bd9Sstevel@tonic-gate 	} while (conn != *connp);
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	return (0);
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate static void
12137c478bd9Sstevel@tonic-gate cots_listen_event(int fd, int conn_index)
12147c478bd9Sstevel@tonic-gate {
12157c478bd9Sstevel@tonic-gate 	struct t_call *call;
12167c478bd9Sstevel@tonic-gate 	struct conn_ind	*conn;
12177c478bd9Sstevel@tonic-gate 	struct conn_ind	*conn_head;
12187c478bd9Sstevel@tonic-gate 	int event;
12197c478bd9Sstevel@tonic-gate 	struct netconfig *nconf = &conn_polled[conn_index].nc;
12207c478bd9Sstevel@tonic-gate 	int new_fd;
12217c478bd9Sstevel@tonic-gate 	struct netbuf addrmask;
12227c478bd9Sstevel@tonic-gate 	int ret = 0;
12237c478bd9Sstevel@tonic-gate 	char *clnt;
12247c478bd9Sstevel@tonic-gate 	char *clnt_uaddr = NULL;
12257c478bd9Sstevel@tonic-gate 	struct nd_hostservlist *clnt_serv = NULL;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	conn_head = (struct conn_ind *)0;
12287c478bd9Sstevel@tonic-gate 	(void) conn_get(fd, nconf, &conn_head);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	while ((conn = conn_head) != NULL) {
12317c478bd9Sstevel@tonic-gate 		conn_head = conn->conn_next;
12327c478bd9Sstevel@tonic-gate 		if (conn_head == conn)
12337c478bd9Sstevel@tonic-gate 			conn_head = (struct conn_ind *)0;
12347c478bd9Sstevel@tonic-gate 		else {
12357c478bd9Sstevel@tonic-gate 			conn_head->conn_prev = conn->conn_prev;
12367c478bd9Sstevel@tonic-gate 			conn->conn_prev->conn_next = conn_head;
12377c478bd9Sstevel@tonic-gate 		}
12387c478bd9Sstevel@tonic-gate 		call = conn->conn_call;
12397c478bd9Sstevel@tonic-gate 		free((char *)conn);
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 		/*
12427c478bd9Sstevel@tonic-gate 		 * If we have already accepted the maximum number of
12437c478bd9Sstevel@tonic-gate 		 * connections allowed on the command line, then drop
12447c478bd9Sstevel@tonic-gate 		 * the oldest connection (for any protocol) before
12457c478bd9Sstevel@tonic-gate 		 * accepting the new connection.  Unless explicitly
12467c478bd9Sstevel@tonic-gate 		 * set on the command line, max_conns_allowed is -1.
12477c478bd9Sstevel@tonic-gate 		 */
12487c478bd9Sstevel@tonic-gate 		if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
12497c478bd9Sstevel@tonic-gate 			conn_close_oldest();
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 		/*
12527c478bd9Sstevel@tonic-gate 		 * Create a new transport endpoint for the same proto as
12537c478bd9Sstevel@tonic-gate 		 * the listener.
12547c478bd9Sstevel@tonic-gate 		 */
12557c478bd9Sstevel@tonic-gate 		new_fd = nfslib_transport_open(nconf);
12567c478bd9Sstevel@tonic-gate 		if (new_fd == -1) {
12577c478bd9Sstevel@tonic-gate 			call->udata.len = 0;
12587c478bd9Sstevel@tonic-gate 			(void) t_snddis(fd, call);
12597c478bd9Sstevel@tonic-gate 			(void) t_free((char *)call, T_CALL);
12607c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "Cannot establish transport over %s",
12617c478bd9Sstevel@tonic-gate 				nconf->nc_device);
12627c478bd9Sstevel@tonic-gate 			continue;
12637c478bd9Sstevel@tonic-gate 		}
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 		/* Bind to a generic address/port for the accepting stream. */
12667c478bd9Sstevel@tonic-gate 		if (t_bind(new_fd, (struct t_bind *)NULL,
12677c478bd9Sstevel@tonic-gate 		    (struct t_bind *)NULL) == -1) {
12687c478bd9Sstevel@tonic-gate 			nfslib_log_tli_error("t_bind", new_fd, nconf);
12697c478bd9Sstevel@tonic-gate 			call->udata.len = 0;
12707c478bd9Sstevel@tonic-gate 			(void) t_snddis(fd, call);
12717c478bd9Sstevel@tonic-gate 			(void) t_free((char *)call, T_CALL);
12727c478bd9Sstevel@tonic-gate 			(void) t_close(new_fd);
12737c478bd9Sstevel@tonic-gate 			continue;
12747c478bd9Sstevel@tonic-gate 		}
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 		while (t_accept(fd, new_fd, call) == -1) {
12777c478bd9Sstevel@tonic-gate 			if (t_errno != TLOOK) {
12787c478bd9Sstevel@tonic-gate #ifdef DEBUG
12797c478bd9Sstevel@tonic-gate 				nfslib_log_tli_error("t_accept", fd, nconf);
12807c478bd9Sstevel@tonic-gate #endif
12817c478bd9Sstevel@tonic-gate 				call->udata.len = 0;
12827c478bd9Sstevel@tonic-gate 				(void) t_snddis(fd, call);
12837c478bd9Sstevel@tonic-gate 				(void) t_free((char *)call, T_CALL);
12847c478bd9Sstevel@tonic-gate 				(void) t_close(new_fd);
12857c478bd9Sstevel@tonic-gate 				goto do_next_conn;
12867c478bd9Sstevel@tonic-gate 			}
12877c478bd9Sstevel@tonic-gate 			while (event = t_look(fd)) {
12887c478bd9Sstevel@tonic-gate 				switch (event) {
12897c478bd9Sstevel@tonic-gate 				case T_LISTEN:
12907c478bd9Sstevel@tonic-gate #ifdef DEBUG
12917c478bd9Sstevel@tonic-gate 					printf(
12927c478bd9Sstevel@tonic-gate "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
12937c478bd9Sstevel@tonic-gate #endif
12947c478bd9Sstevel@tonic-gate 					(void) conn_get(fd, nconf, &conn_head);
12957c478bd9Sstevel@tonic-gate 					continue;
12967c478bd9Sstevel@tonic-gate 				case T_DISCONNECT:
12977c478bd9Sstevel@tonic-gate #ifdef DEBUG
12987c478bd9Sstevel@tonic-gate 					printf(
12997c478bd9Sstevel@tonic-gate 	"cots_listen_event(%s): T_DISCONNECT during accept processing\n",
13007c478bd9Sstevel@tonic-gate 						nconf->nc_proto);
13017c478bd9Sstevel@tonic-gate #endif
13027c478bd9Sstevel@tonic-gate 					(void) discon_get(fd, nconf,
13037c478bd9Sstevel@tonic-gate 								&conn_head);
13047c478bd9Sstevel@tonic-gate 					continue;
13057c478bd9Sstevel@tonic-gate 				default:
13067c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
13077c478bd9Sstevel@tonic-gate 			"unexpected event 0x%x during accept processing (%s)",
13087c478bd9Sstevel@tonic-gate 						event, nconf->nc_proto);
13097c478bd9Sstevel@tonic-gate 					call->udata.len = 0;
13107c478bd9Sstevel@tonic-gate 					(void) t_snddis(fd, call);
13117c478bd9Sstevel@tonic-gate 					(void) t_free((char *)call, T_CALL);
13127c478bd9Sstevel@tonic-gate 					(void) t_close(new_fd);
13137c478bd9Sstevel@tonic-gate 					goto do_next_conn;
13147c478bd9Sstevel@tonic-gate 				}
13157c478bd9Sstevel@tonic-gate 			}
13167c478bd9Sstevel@tonic-gate 		}
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 		if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
13197c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
13207c478bd9Sstevel@tonic-gate 			    "Cannot set address mask for %s",
13217c478bd9Sstevel@tonic-gate 				nconf->nc_netid);
13227c478bd9Sstevel@tonic-gate 			return;
13237c478bd9Sstevel@tonic-gate 		}
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 		/* Tell KRPC about the new stream. */
13267c478bd9Sstevel@tonic-gate 		if (Mysvc4 != NULL)
13277c478bd9Sstevel@tonic-gate 			ret = (*Mysvc4)(new_fd, &addrmask, nconf,
13287c478bd9Sstevel@tonic-gate 				NFS4_KRPC_START, &call->addr);
13297c478bd9Sstevel@tonic-gate 		else
13307c478bd9Sstevel@tonic-gate 			ret = (*Mysvc)(new_fd, addrmask, nconf);
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 		if (ret < 0) {
13337c478bd9Sstevel@tonic-gate 			if (errno != ENOTCONN) {
13347c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR,
13357c478bd9Sstevel@tonic-gate 				    "unable to register new connection: %m");
13367c478bd9Sstevel@tonic-gate 			} else {
13377c478bd9Sstevel@tonic-gate 				/*
13387c478bd9Sstevel@tonic-gate 				 * This is the only error that could be
13397c478bd9Sstevel@tonic-gate 				 * caused by the client, so who was it?
13407c478bd9Sstevel@tonic-gate 				 */
13417c478bd9Sstevel@tonic-gate 				if (netdir_getbyaddr(nconf, &clnt_serv,
13427c478bd9Sstevel@tonic-gate 				    &(call->addr)) == ND_OK &&
13437c478bd9Sstevel@tonic-gate 				    clnt_serv->h_cnt > 0)
13447c478bd9Sstevel@tonic-gate 					clnt = clnt_serv->h_hostservs->h_host;
13457c478bd9Sstevel@tonic-gate 				else
13467c478bd9Sstevel@tonic-gate 					clnt = clnt_uaddr = taddr2uaddr(nconf,
13477c478bd9Sstevel@tonic-gate 					    &(call->addr));
13487c478bd9Sstevel@tonic-gate 				/*
13497c478bd9Sstevel@tonic-gate 				 * If we don't know who the client was,
13507c478bd9Sstevel@tonic-gate 				 * remain silent.
13517c478bd9Sstevel@tonic-gate 				 */
13527c478bd9Sstevel@tonic-gate 				if (clnt)
13537c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
13547c478bd9Sstevel@tonic-gate "unable to register new connection: client %s has dropped connection", clnt);
13557c478bd9Sstevel@tonic-gate 				if (clnt_serv)
13567c478bd9Sstevel@tonic-gate 					netdir_free(clnt_serv, ND_HOSTSERVLIST);
13577c478bd9Sstevel@tonic-gate 				if (clnt_uaddr)
13587c478bd9Sstevel@tonic-gate 					free(clnt_uaddr);
13597c478bd9Sstevel@tonic-gate 			}
13607c478bd9Sstevel@tonic-gate 			free(addrmask.buf);
13617c478bd9Sstevel@tonic-gate 			(void) t_snddis(new_fd, (struct t_call *)0);
13627c478bd9Sstevel@tonic-gate 			(void) t_free((char *)call, T_CALL);
13637c478bd9Sstevel@tonic-gate 			(void) t_close(new_fd);
13647c478bd9Sstevel@tonic-gate 			goto do_next_conn;
13657c478bd9Sstevel@tonic-gate 		}
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 		free(addrmask.buf);
13687c478bd9Sstevel@tonic-gate 		(void) t_free((char *)call, T_CALL);
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 		/*
13717c478bd9Sstevel@tonic-gate 		 * Poll on the new descriptor so that we get disconnect
13727c478bd9Sstevel@tonic-gate 		 * and orderly release indications.
13737c478bd9Sstevel@tonic-gate 		 */
13747c478bd9Sstevel@tonic-gate 		num_conns++;
13757c478bd9Sstevel@tonic-gate 		add_to_poll_list(new_fd, nconf);
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 		/* Reset nconf in case it has been moved. */
13787c478bd9Sstevel@tonic-gate 		nconf = &conn_polled[conn_index].nc;
13797c478bd9Sstevel@tonic-gate do_next_conn:;
13807c478bd9Sstevel@tonic-gate 	}
13817c478bd9Sstevel@tonic-gate }
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate static int
13847c478bd9Sstevel@tonic-gate do_poll_cots_action(int fd, int conn_index)
13857c478bd9Sstevel@tonic-gate {
13867c478bd9Sstevel@tonic-gate 	char buf[256];
13877c478bd9Sstevel@tonic-gate 	int event;
13887c478bd9Sstevel@tonic-gate 	int i1;
13897c478bd9Sstevel@tonic-gate 	int flags;
13907c478bd9Sstevel@tonic-gate 	struct conn_entry *connent = &conn_polled[conn_index];
13917c478bd9Sstevel@tonic-gate 	struct netconfig *nconf = &(connent->nc);
13927c478bd9Sstevel@tonic-gate 	const char *errorstr;
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	while (event = t_look(fd)) {
13957c478bd9Sstevel@tonic-gate 		switch (event) {
13967c478bd9Sstevel@tonic-gate 		case T_LISTEN:
13977c478bd9Sstevel@tonic-gate #ifdef DEBUG
13987c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd);
13997c478bd9Sstevel@tonic-gate #endif
14007c478bd9Sstevel@tonic-gate 			cots_listen_event(fd, conn_index);
14017c478bd9Sstevel@tonic-gate 			break;
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 		case T_DATA:
14047c478bd9Sstevel@tonic-gate #ifdef DEBUG
14057c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto);
14067c478bd9Sstevel@tonic-gate #endif
14077c478bd9Sstevel@tonic-gate 			/*
14087c478bd9Sstevel@tonic-gate 			 * Receive a private notification from CONS rpcmod.
14097c478bd9Sstevel@tonic-gate 			 */
14107c478bd9Sstevel@tonic-gate 			i1 = t_rcv(fd, buf, sizeof (buf), &flags);
14117c478bd9Sstevel@tonic-gate 			if (i1 == -1) {
14127c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "t_rcv failed");
14137c478bd9Sstevel@tonic-gate 				break;
14147c478bd9Sstevel@tonic-gate 			}
14157c478bd9Sstevel@tonic-gate 			if (i1 < sizeof (int))
14167c478bd9Sstevel@tonic-gate 				break;
14177c478bd9Sstevel@tonic-gate 			i1 = BE32_TO_U32(buf);
14187c478bd9Sstevel@tonic-gate 			if (i1 == 1 || i1 == 2) {
14197c478bd9Sstevel@tonic-gate 				/*
14207c478bd9Sstevel@tonic-gate 				 * This connection has been idle for too long,
14217c478bd9Sstevel@tonic-gate 				 * so release it as politely as we can.  If we
14227c478bd9Sstevel@tonic-gate 				 * have already initiated an orderly release
14237c478bd9Sstevel@tonic-gate 				 * and we get notified that the stream is
14247c478bd9Sstevel@tonic-gate 				 * still idle, pull the plug.  This prevents
14257c478bd9Sstevel@tonic-gate 				 * hung connections from continuing to consume
14267c478bd9Sstevel@tonic-gate 				 * resources.
14277c478bd9Sstevel@tonic-gate 				 */
14287c478bd9Sstevel@tonic-gate #ifdef DEBUG
14297c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd);
14307c478bd9Sstevel@tonic-gate printf("initiating orderly release of idle connection\n");
14317c478bd9Sstevel@tonic-gate #endif
14327c478bd9Sstevel@tonic-gate 				if (nconf->nc_semantics == NC_TPI_COTS ||
14337c478bd9Sstevel@tonic-gate 					connent->closing != 0) {
14347c478bd9Sstevel@tonic-gate 					(void) t_snddis(fd, (struct t_call *)0);
14357c478bd9Sstevel@tonic-gate 					goto fdclose;
14367c478bd9Sstevel@tonic-gate 				}
14377c478bd9Sstevel@tonic-gate 				/*
14387c478bd9Sstevel@tonic-gate 				 * For NC_TPI_COTS_ORD, the stream is closed
14397c478bd9Sstevel@tonic-gate 				 * and removed from the poll list when the
14407c478bd9Sstevel@tonic-gate 				 * T_ORDREL is received from the provider.  We
14417c478bd9Sstevel@tonic-gate 				 * don't wait for it here because it may take
14427c478bd9Sstevel@tonic-gate 				 * a while for the transport to shut down.
14437c478bd9Sstevel@tonic-gate 				 */
14447c478bd9Sstevel@tonic-gate 				if (t_sndrel(fd) == -1) {
14457c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
14467c478bd9Sstevel@tonic-gate 					"unable to send orderly release %m");
14477c478bd9Sstevel@tonic-gate 				}
14487c478bd9Sstevel@tonic-gate 				connent->closing = 1;
14497c478bd9Sstevel@tonic-gate 			} else
14507c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR,
14517c478bd9Sstevel@tonic-gate 				"unexpected event from CONS rpcmod %d", i1);
14527c478bd9Sstevel@tonic-gate 			break;
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 		case T_ORDREL:
14557c478bd9Sstevel@tonic-gate #ifdef DEBUG
14567c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd);
14577c478bd9Sstevel@tonic-gate #endif
14587c478bd9Sstevel@tonic-gate 			/* Perform an orderly release. */
14597c478bd9Sstevel@tonic-gate 			if (t_rcvrel(fd) == 0) {
14607c478bd9Sstevel@tonic-gate 				/* T_ORDREL on listen fd's should be ignored */
14617c478bd9Sstevel@tonic-gate 				if (!is_listen_fd_index(conn_index)) {
14627c478bd9Sstevel@tonic-gate 					(void) t_sndrel(fd);
14637c478bd9Sstevel@tonic-gate 					goto fdclose;
14647c478bd9Sstevel@tonic-gate 				}
14657c478bd9Sstevel@tonic-gate 				break;
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 			} else if (t_errno == TLOOK) {
14687c478bd9Sstevel@tonic-gate 				break;
14697c478bd9Sstevel@tonic-gate 			} else {
14707c478bd9Sstevel@tonic-gate 				nfslib_log_tli_error("t_rcvrel", fd, nconf);
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 				/*
14737c478bd9Sstevel@tonic-gate 				 * check to make sure we do not close
14747c478bd9Sstevel@tonic-gate 				 * listen fd
14757c478bd9Sstevel@tonic-gate 				 */
14767c478bd9Sstevel@tonic-gate 				if (is_listen_fd_index(conn_index))
14777c478bd9Sstevel@tonic-gate 					break;
14787c478bd9Sstevel@tonic-gate 				else
14797c478bd9Sstevel@tonic-gate 					goto fdclose;
14807c478bd9Sstevel@tonic-gate 			}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 		case T_DISCONNECT:
14837c478bd9Sstevel@tonic-gate #ifdef DEBUG
14847c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd);
14857c478bd9Sstevel@tonic-gate #endif
14867c478bd9Sstevel@tonic-gate 			if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
14877c478bd9Sstevel@tonic-gate 				nfslib_log_tli_error("t_rcvdis", fd, nconf);
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 			/*
14907c478bd9Sstevel@tonic-gate 			 * T_DISCONNECT on listen fd's should be ignored.
14917c478bd9Sstevel@tonic-gate 			 */
14927c478bd9Sstevel@tonic-gate 			if (is_listen_fd_index(conn_index))
14937c478bd9Sstevel@tonic-gate 				break;
14947c478bd9Sstevel@tonic-gate 			else
14957c478bd9Sstevel@tonic-gate 				goto fdclose;
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 		case T_ERROR:
14987c478bd9Sstevel@tonic-gate 		default:
14997c478bd9Sstevel@tonic-gate 			if (event == T_ERROR || t_errno == TSYSERR) {
15007c478bd9Sstevel@tonic-gate 			    if ((errorstr = strerror(errno)) == NULL) {
15017c478bd9Sstevel@tonic-gate 				(void) sprintf(buf, "Unknown error num %d",
15027c478bd9Sstevel@tonic-gate 									errno);
15037c478bd9Sstevel@tonic-gate 				errorstr = (const char *) buf;
15047c478bd9Sstevel@tonic-gate 			    }
15057c478bd9Sstevel@tonic-gate 			} else if (event == -1)
15067c478bd9Sstevel@tonic-gate 				errorstr = t_strerror(t_errno);
15077c478bd9Sstevel@tonic-gate 			else
15087c478bd9Sstevel@tonic-gate 				errorstr = "";
15097c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
15107c478bd9Sstevel@tonic-gate 			    "unexpected TLI event (0x%x) on "
15117c478bd9Sstevel@tonic-gate 			    "connection-oriented transport(%s,%d):%s",
15127c478bd9Sstevel@tonic-gate 			    event, nconf->nc_proto, fd, errorstr);
15137c478bd9Sstevel@tonic-gate fdclose:
15147c478bd9Sstevel@tonic-gate 			num_conns--;
15157c478bd9Sstevel@tonic-gate 			remove_from_poll_list(fd);
15167c478bd9Sstevel@tonic-gate 			(void) t_close(fd);
15177c478bd9Sstevel@tonic-gate 			return (0);
15187c478bd9Sstevel@tonic-gate 		}
15197c478bd9Sstevel@tonic-gate 	}
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	return (0);
15227c478bd9Sstevel@tonic-gate }
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate static char *
15257c478bd9Sstevel@tonic-gate serv_name_to_port_name(char *name)
15267c478bd9Sstevel@tonic-gate {
15277c478bd9Sstevel@tonic-gate 	/*
15287c478bd9Sstevel@tonic-gate 	 * Map service names (used primarily in logging) to
15297c478bd9Sstevel@tonic-gate 	 * RPC port names (used by netdir_*() routines).
15307c478bd9Sstevel@tonic-gate 	 */
15317c478bd9Sstevel@tonic-gate 	if (strcmp(name, "NFS") == 0) {
15327c478bd9Sstevel@tonic-gate 		return ("nfs");
15337c478bd9Sstevel@tonic-gate 	} else if (strcmp(name, "NLM") == 0) {
15347c478bd9Sstevel@tonic-gate 		return ("lockd");
15357c478bd9Sstevel@tonic-gate 	} else if (strcmp(name, "NFS4_CALLBACK") == 0) {
15367c478bd9Sstevel@tonic-gate 		return ("nfs4_callback");
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	return ("unrecognized");
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate static int
15437c478bd9Sstevel@tonic-gate bind_to_provider(char *provider, char *serv, struct netbuf **addr,
15447c478bd9Sstevel@tonic-gate 		struct netconfig **retnconf)
15457c478bd9Sstevel@tonic-gate {
15467c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
15477c478bd9Sstevel@tonic-gate 	NCONF_HANDLE *nc;
15487c478bd9Sstevel@tonic-gate 	struct nd_hostserv hs;
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	hs.h_host = HOST_SELF;
15517c478bd9Sstevel@tonic-gate 	hs.h_serv = serv_name_to_port_name(serv);
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
15547c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "setnetconfig failed: %m");
15557c478bd9Sstevel@tonic-gate 		return (-1);
15567c478bd9Sstevel@tonic-gate 	}
15577c478bd9Sstevel@tonic-gate 	while (nconf = getnetconfig(nc)) {
15587c478bd9Sstevel@tonic-gate 		if (OK_TPI_TYPE(nconf) &&
15597c478bd9Sstevel@tonic-gate 		    strcmp(nconf->nc_device, provider) == 0) {
15607c478bd9Sstevel@tonic-gate 			*retnconf = nconf;
15617c478bd9Sstevel@tonic-gate 			return (nfslib_bindit(nconf, addr, &hs,
15627c478bd9Sstevel@tonic-gate 					listen_backlog));
15637c478bd9Sstevel@tonic-gate 		}
15647c478bd9Sstevel@tonic-gate 	}
15657c478bd9Sstevel@tonic-gate 	(void) endnetconfig(nc);
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
15687c478bd9Sstevel@tonic-gate 	    provider);
15697c478bd9Sstevel@tonic-gate 	return (-1);
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate static int
15737c478bd9Sstevel@tonic-gate bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
15747c478bd9Sstevel@tonic-gate 		struct netconfig **retnconf)
15757c478bd9Sstevel@tonic-gate {
15767c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
15777c478bd9Sstevel@tonic-gate 	NCONF_HANDLE *nc = NULL;
15787c478bd9Sstevel@tonic-gate 	struct nd_hostserv hs;
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	hs.h_host = HOST_SELF;
15817c478bd9Sstevel@tonic-gate 	hs.h_serv = serv_name_to_port_name(serv);
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
15847c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "setnetconfig failed: %m");
15857c478bd9Sstevel@tonic-gate 		return (-1);
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate 	while (nconf = getnetconfig(nc)) {
15887c478bd9Sstevel@tonic-gate 		if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
15897c478bd9Sstevel@tonic-gate 			*retnconf = nconf;
15907c478bd9Sstevel@tonic-gate 			return (nfslib_bindit(nconf, addr, &hs,
15917c478bd9Sstevel@tonic-gate 					listen_backlog));
15927c478bd9Sstevel@tonic-gate 		}
15937c478bd9Sstevel@tonic-gate 	}
15947c478bd9Sstevel@tonic-gate 	(void) endnetconfig(nc);
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",
15977c478bd9Sstevel@tonic-gate 	    proto);
15987c478bd9Sstevel@tonic-gate 	return (-1);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate #include <netinet/in.h>
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate /*
16047c478bd9Sstevel@tonic-gate  * Create an address mask appropriate for the transport.
16057c478bd9Sstevel@tonic-gate  * The mask is used to obtain the host-specific part of
16067c478bd9Sstevel@tonic-gate  * a network address when comparing addresses.
16077c478bd9Sstevel@tonic-gate  * For an internet address the host-specific part is just
16087c478bd9Sstevel@tonic-gate  * the 32 bit IP address and this part of the mask is set
16097c478bd9Sstevel@tonic-gate  * to all-ones. The port number part of the mask is zeroes.
16107c478bd9Sstevel@tonic-gate  */
16117c478bd9Sstevel@tonic-gate static int
16127c478bd9Sstevel@tonic-gate set_addrmask(fd, nconf, mask)
16137c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
16147c478bd9Sstevel@tonic-gate 	struct netbuf *mask;
16157c478bd9Sstevel@tonic-gate {
16167c478bd9Sstevel@tonic-gate 	struct t_info info;
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	/*
16197c478bd9Sstevel@tonic-gate 	 * Find the size of the address we need to mask.
16207c478bd9Sstevel@tonic-gate 	 */
16217c478bd9Sstevel@tonic-gate 	if (t_getinfo(fd, &info) < 0) {
16227c478bd9Sstevel@tonic-gate 		t_error("t_getinfo");
16237c478bd9Sstevel@tonic-gate 		return (-1);
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 	mask->len = mask->maxlen = info.addr;
16267c478bd9Sstevel@tonic-gate 	if (info.addr <= 0) {
16277c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "set_addrmask: address size: %ld",
16287c478bd9Sstevel@tonic-gate 			info.addr);
16297c478bd9Sstevel@tonic-gate 		return (-1);
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	mask->buf = (char *)malloc(mask->len);
16337c478bd9Sstevel@tonic-gate 	if (mask->buf == NULL) {
16347c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "set_addrmask: no memory");
16357c478bd9Sstevel@tonic-gate 		return (-1);
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate 	(void) memset(mask->buf, 0, mask->len);	/* reset all mask bits */
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
16407c478bd9Sstevel@tonic-gate 		/*
16417c478bd9Sstevel@tonic-gate 		 * Set the mask so that the port is ignored.
16427c478bd9Sstevel@tonic-gate 		 */
16437c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
16447c478bd9Sstevel@tonic-gate 		((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
16457c478bd9Sstevel@tonic-gate 								(ulong_t)~0;
16467c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
16477c478bd9Sstevel@tonic-gate 		((struct sockaddr_in *)mask->buf)->sin_family =
16487c478bd9Sstevel@tonic-gate 								(ushort_t)~0;
16497c478bd9Sstevel@tonic-gate 	} else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
16507c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
16517c478bd9Sstevel@tonic-gate 		(void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
16527c478bd9Sstevel@tonic-gate 			(uchar_t)~0, sizeof (struct in6_addr));
16537c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
16547c478bd9Sstevel@tonic-gate 		((struct sockaddr_in6 *)mask->buf)->sin6_family =
16557c478bd9Sstevel@tonic-gate 								(ushort_t)~0;
16567c478bd9Sstevel@tonic-gate 	} else {
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 		/*
16597c478bd9Sstevel@tonic-gate 		 * Set all mask bits.
16607c478bd9Sstevel@tonic-gate 		 */
16617c478bd9Sstevel@tonic-gate 		(void) memset(mask->buf, 0xFF, mask->len);
16627c478bd9Sstevel@tonic-gate 	}
16637c478bd9Sstevel@tonic-gate 	return (0);
16647c478bd9Sstevel@tonic-gate }
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate /*
16677c478bd9Sstevel@tonic-gate  * For listen fd's index is always less than end_listen_fds.
16687c478bd9Sstevel@tonic-gate  * end_listen_fds is defined externally in the daemon that uses this library.
16697c478bd9Sstevel@tonic-gate  * It's value is equal to the number of open file descriptors after the
16707c478bd9Sstevel@tonic-gate  * last listen end point was opened but before any connection was accepted.
16717c478bd9Sstevel@tonic-gate  */
16727c478bd9Sstevel@tonic-gate static int
16737c478bd9Sstevel@tonic-gate is_listen_fd_index(int index)
16747c478bd9Sstevel@tonic-gate {
16757c478bd9Sstevel@tonic-gate 	return (index < end_listen_fds);
16767c478bd9Sstevel@tonic-gate }
1677