10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51676Sjpk * Common Development and Distribution License (the "License"). 61676Sjpk * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*10004Sdai.ngo@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * nfs_tbind.c, common part for nfsd and lockd. 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 302712Snn35248 #define PORTMAP 312712Snn35248 320Sstevel@tonic-gate #include <tiuser.h> 330Sstevel@tonic-gate #include <fcntl.h> 340Sstevel@tonic-gate #include <netconfig.h> 350Sstevel@tonic-gate #include <stropts.h> 360Sstevel@tonic-gate #include <errno.h> 370Sstevel@tonic-gate #include <syslog.h> 380Sstevel@tonic-gate #include <rpc/rpc.h> 392712Snn35248 #include <rpc/pmap_prot.h> 400Sstevel@tonic-gate #include <sys/time.h> 410Sstevel@tonic-gate #include <sys/resource.h> 420Sstevel@tonic-gate #include <signal.h> 430Sstevel@tonic-gate #include <netdir.h> 440Sstevel@tonic-gate #include <unistd.h> 450Sstevel@tonic-gate #include <string.h> 460Sstevel@tonic-gate #include <netinet/tcp.h> 470Sstevel@tonic-gate #include <malloc.h> 480Sstevel@tonic-gate #include <stdlib.h> 490Sstevel@tonic-gate #include "nfs_tbind.h" 500Sstevel@tonic-gate #include <nfs/nfs.h> 510Sstevel@tonic-gate #include <nfs/nfs_acl.h> 520Sstevel@tonic-gate #include <nfs/nfssys.h> 530Sstevel@tonic-gate #include <nfs/nfs4.h> 541676Sjpk #include <zone.h> 551676Sjpk #include <sys/socket.h> 561676Sjpk #include <tsol/label.h> 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * Determine valid semantics for most applications. 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate #define OK_TPI_TYPE(_nconf) \ 620Sstevel@tonic-gate (_nconf->nc_semantics == NC_TPI_CLTS || \ 630Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS || \ 640Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS_ORD) 650Sstevel@tonic-gate 660Sstevel@tonic-gate #define BE32_TO_U32(a) \ 670Sstevel@tonic-gate ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \ 680Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \ 690Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \ 700Sstevel@tonic-gate ((ulong_t)((uchar_t *)a)[3] & 0xFF)) 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * Number of elements to add to the poll array on each allocation. 740Sstevel@tonic-gate */ 750Sstevel@tonic-gate #define POLL_ARRAY_INC_SIZE 64 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* 780Sstevel@tonic-gate * Number of file descriptors by which the process soft limit may be 790Sstevel@tonic-gate * increased on each call to nofile_increase(0). 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate #define NOFILE_INC_SIZE 64 820Sstevel@tonic-gate 83*10004Sdai.ngo@sun.com /* 84*10004Sdai.ngo@sun.com * Default TCP send and receive buffer size of NFS server. 85*10004Sdai.ngo@sun.com */ 86*10004Sdai.ngo@sun.com #define NFSD_TCP_BUFSZ (1024*1024) 87*10004Sdai.ngo@sun.com 880Sstevel@tonic-gate struct conn_ind { 890Sstevel@tonic-gate struct conn_ind *conn_next; 900Sstevel@tonic-gate struct conn_ind *conn_prev; 910Sstevel@tonic-gate struct t_call *conn_call; 920Sstevel@tonic-gate }; 930Sstevel@tonic-gate 940Sstevel@tonic-gate struct conn_entry { 950Sstevel@tonic-gate bool_t closing; 960Sstevel@tonic-gate struct netconfig nc; 970Sstevel@tonic-gate }; 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * this file contains transport routines common to nfsd and lockd 1010Sstevel@tonic-gate */ 1020Sstevel@tonic-gate static int nofile_increase(int); 1030Sstevel@tonic-gate static int reuseaddr(int); 1041676Sjpk static int recvucred(int); 1051676Sjpk static int anonmlp(int); 1060Sstevel@tonic-gate static void add_to_poll_list(int, struct netconfig *); 1070Sstevel@tonic-gate static char *serv_name_to_port_name(char *); 1080Sstevel@tonic-gate static int bind_to_proto(char *, char *, struct netbuf **, 1090Sstevel@tonic-gate struct netconfig **); 1100Sstevel@tonic-gate static int bind_to_provider(char *, char *, struct netbuf **, 1110Sstevel@tonic-gate struct netconfig **); 1120Sstevel@tonic-gate static void conn_close_oldest(void); 1130Sstevel@tonic-gate static boolean_t conn_get(int, struct netconfig *, struct conn_ind **); 1140Sstevel@tonic-gate static void cots_listen_event(int, int); 1150Sstevel@tonic-gate static int discon_get(int, struct netconfig *, struct conn_ind **); 1160Sstevel@tonic-gate static int do_poll_clts_action(int, int); 1170Sstevel@tonic-gate static int do_poll_cots_action(int, int); 1180Sstevel@tonic-gate static void remove_from_poll_list(int); 1190Sstevel@tonic-gate static int set_addrmask(int, struct netconfig *, struct netbuf *); 1200Sstevel@tonic-gate static int is_listen_fd_index(int); 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static struct pollfd *poll_array; 1230Sstevel@tonic-gate static struct conn_entry *conn_polled; 1240Sstevel@tonic-gate static int num_conns; /* Current number of connections */ 1250Sstevel@tonic-gate int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int, 1260Sstevel@tonic-gate struct netbuf *); 127*10004Sdai.ngo@sun.com static int setopt(int fd, int level, int name, int value); 128*10004Sdai.ngo@sun.com static int get_opt(int fd, int level, int name); 129*10004Sdai.ngo@sun.com static void nfslib_set_sockbuf(int fd); 1300Sstevel@tonic-gate 1312712Snn35248 extern bool_t __pmap_set(const rpcprog_t program, const rpcvers_t version, 1322712Snn35248 const struct netconfig *nconf, const struct netbuf *address); 1332712Snn35248 1340Sstevel@tonic-gate /* 1350Sstevel@tonic-gate * Called to create and prepare a transport descriptor for in-kernel 1360Sstevel@tonic-gate * RPC service. 1370Sstevel@tonic-gate * Returns -1 on failure and a valid descriptor on success. 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate int 1400Sstevel@tonic-gate nfslib_transport_open(struct netconfig *nconf) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate int fd; 1430Sstevel@tonic-gate struct strioctl strioc; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate if ((nconf == (struct netconfig *)NULL) || 1460Sstevel@tonic-gate (nconf->nc_device == (char *)NULL)) { 1470Sstevel@tonic-gate syslog(LOG_ERR, "no netconfig device"); 1480Sstevel@tonic-gate return (-1); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * Open the transport device. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL); 1550Sstevel@tonic-gate if (fd == -1) { 1560Sstevel@tonic-gate if (t_errno == TSYSERR && errno == EMFILE && 1570Sstevel@tonic-gate (nofile_increase(0) == 0)) { 1580Sstevel@tonic-gate /* Try again with a higher NOFILE limit. */ 1590Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, 1607208Svv149972 (struct t_info *)NULL); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate if (fd == -1) { 1630Sstevel@tonic-gate syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m", 1640Sstevel@tonic-gate nconf->nc_device, t_errno); 1650Sstevel@tonic-gate return (-1); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * Pop timod because the RPC module must be as close as possible 1710Sstevel@tonic-gate * to the transport. 1720Sstevel@tonic-gate */ 1730Sstevel@tonic-gate if (ioctl(fd, I_POP, 0) < 0) { 1740Sstevel@tonic-gate syslog(LOG_ERR, "I_POP of timod failed: %m"); 1750Sstevel@tonic-gate (void) t_close(fd); 1760Sstevel@tonic-gate return (-1); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * Common code for CLTS and COTS transports 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "rpcmod") < 0) { 1830Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m"); 1840Sstevel@tonic-gate (void) t_close(fd); 1850Sstevel@tonic-gate return (-1); 1860Sstevel@tonic-gate } 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate strioc.ic_cmd = RPC_SERVER; 1890Sstevel@tonic-gate strioc.ic_dp = (char *)0; 1900Sstevel@tonic-gate strioc.ic_len = 0; 1910Sstevel@tonic-gate strioc.ic_timout = -1; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* Tell rpcmod to act like a server stream. */ 1940Sstevel@tonic-gate if (ioctl(fd, I_STR, &strioc) < 0) { 1950Sstevel@tonic-gate syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m"); 1960Sstevel@tonic-gate (void) t_close(fd); 1970Sstevel@tonic-gate return (-1); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* 2010Sstevel@tonic-gate * Re-push timod so that we will still be doing TLI 2020Sstevel@tonic-gate * operations on the descriptor. 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "timod") < 0) { 2050Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of timod failed: %m"); 2060Sstevel@tonic-gate (void) t_close(fd); 2070Sstevel@tonic-gate return (-1); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2107208Svv149972 /* 2117208Svv149972 * Enable options of returning the ip's for udp. 2127208Svv149972 */ 2137208Svv149972 if (strcmp(nconf->nc_netid, "udp6") == 0) 2147208Svv149972 __rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1); 2157208Svv149972 else if (strcmp(nconf->nc_netid, "udp") == 0) 2167208Svv149972 __rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1); 2177208Svv149972 2180Sstevel@tonic-gate return (fd); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate static int 2220Sstevel@tonic-gate nofile_increase(int limit) 2230Sstevel@tonic-gate { 2240Sstevel@tonic-gate struct rlimit rl; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { 2270Sstevel@tonic-gate syslog(LOG_ERR, "getrlimit of NOFILE failed: %m"); 2280Sstevel@tonic-gate return (-1); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (limit > 0) 2320Sstevel@tonic-gate rl.rlim_cur = limit; 2330Sstevel@tonic-gate else 2340Sstevel@tonic-gate rl.rlim_cur += NOFILE_INC_SIZE; 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if (rl.rlim_cur > rl.rlim_max && 2370Sstevel@tonic-gate rl.rlim_max != RLIM_INFINITY) 2380Sstevel@tonic-gate rl.rlim_max = rl.rlim_cur; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 2410Sstevel@tonic-gate syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m", 2427208Svv149972 rl.rlim_cur); 2430Sstevel@tonic-gate return (-1); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate return (0); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 249*10004Sdai.ngo@sun.com static void 250*10004Sdai.ngo@sun.com nfslib_set_sockbuf(int fd) 251*10004Sdai.ngo@sun.com { 252*10004Sdai.ngo@sun.com int curval, val; 253*10004Sdai.ngo@sun.com 254*10004Sdai.ngo@sun.com val = NFSD_TCP_BUFSZ; 255*10004Sdai.ngo@sun.com 256*10004Sdai.ngo@sun.com curval = get_opt(fd, SOL_SOCKET, SO_SNDBUF); 257*10004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Current SO_SNDBUF value is %d", curval); 258*10004Sdai.ngo@sun.com if ((curval != -1) && (curval < val)) { 259*10004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Set SO_SNDBUF option to %d", val); 260*10004Sdai.ngo@sun.com if (setopt(fd, SOL_SOCKET, SO_SNDBUF, val) < 0) { 261*10004Sdai.ngo@sun.com syslog(LOG_ERR, 262*10004Sdai.ngo@sun.com "couldn't set SO_SNDBUF to %d - t_errno = %d", 263*10004Sdai.ngo@sun.com val, t_errno); 264*10004Sdai.ngo@sun.com syslog(LOG_ERR, 265*10004Sdai.ngo@sun.com "Check and increase system-wide tcp_max_buf"); 266*10004Sdai.ngo@sun.com } 267*10004Sdai.ngo@sun.com } 268*10004Sdai.ngo@sun.com 269*10004Sdai.ngo@sun.com curval = get_opt(fd, SOL_SOCKET, SO_RCVBUF); 270*10004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Current SO_RCVBUF value is %d", curval); 271*10004Sdai.ngo@sun.com if ((curval != -1) && (curval < val)) { 272*10004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Set SO_RCVBUF option to %d", val); 273*10004Sdai.ngo@sun.com if (setopt(fd, SOL_SOCKET, SO_RCVBUF, val) < 0) { 274*10004Sdai.ngo@sun.com syslog(LOG_ERR, 275*10004Sdai.ngo@sun.com "couldn't set SO_RCVBUF to %d - t_errno = %d", 276*10004Sdai.ngo@sun.com val, t_errno); 277*10004Sdai.ngo@sun.com syslog(LOG_ERR, 278*10004Sdai.ngo@sun.com "Check and increase system-wide tcp_max_buf"); 279*10004Sdai.ngo@sun.com } 280*10004Sdai.ngo@sun.com } 281*10004Sdai.ngo@sun.com } 282*10004Sdai.ngo@sun.com 2830Sstevel@tonic-gate int 2840Sstevel@tonic-gate nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, 2850Sstevel@tonic-gate struct nd_hostserv *hs, int backlog) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate int fd; 2880Sstevel@tonic-gate struct t_bind *ntb; 2890Sstevel@tonic-gate struct t_bind tb; 2900Sstevel@tonic-gate struct nd_addrlist *addrlist; 2910Sstevel@tonic-gate struct t_optmgmt req, resp; 2920Sstevel@tonic-gate struct opthdr *opt; 2930Sstevel@tonic-gate char reqbuf[128]; 2940Sstevel@tonic-gate bool_t use_any = FALSE; 2951676Sjpk bool_t gzone = TRUE; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate if ((fd = nfslib_transport_open(nconf)) == -1) { 2980Sstevel@tonic-gate syslog(LOG_ERR, "cannot establish transport service over %s", 2997208Svv149972 nconf->nc_device); 3000Sstevel@tonic-gate return (-1); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate addrlist = (struct nd_addrlist *)NULL; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /* nfs4_callback service does not used a fieed port number */ 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate if (strcmp(hs->h_serv, "nfs4_callback") == 0) { 3080Sstevel@tonic-gate tb.addr.maxlen = 0; 3090Sstevel@tonic-gate tb.addr.len = 0; 3100Sstevel@tonic-gate tb.addr.buf = 0; 3110Sstevel@tonic-gate use_any = TRUE; 3121676Sjpk gzone = (getzoneid() == GLOBAL_ZONEID); 3130Sstevel@tonic-gate } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) { 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate syslog(LOG_ERR, 3160Sstevel@tonic-gate "Cannot get address for transport %s host %s service %s", 3177208Svv149972 nconf->nc_netid, hs->h_host, hs->h_serv); 3180Sstevel@tonic-gate (void) t_close(fd); 3190Sstevel@tonic-gate return (-1); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) { 3230Sstevel@tonic-gate /* 3240Sstevel@tonic-gate * If we're running over TCP, then set the 3250Sstevel@tonic-gate * SO_REUSEADDR option so that we can bind 3260Sstevel@tonic-gate * to our preferred address even if previously 3270Sstevel@tonic-gate * left connections exist in FIN_WAIT states. 3280Sstevel@tonic-gate * This is somewhat bogus, but otherwise you have 3290Sstevel@tonic-gate * to wait 2 minutes to restart after killing it. 3300Sstevel@tonic-gate */ 3310Sstevel@tonic-gate if (reuseaddr(fd) == -1) { 3320Sstevel@tonic-gate syslog(LOG_WARNING, 3330Sstevel@tonic-gate "couldn't set SO_REUSEADDR option on transport"); 3340Sstevel@tonic-gate } 3351676Sjpk } else if (strcmp(nconf->nc_proto, "udp") == 0) { 3361676Sjpk /* 3371676Sjpk * In order to run MLP on UDP, we need to handle creds. 3381676Sjpk */ 3391676Sjpk if (recvucred(fd) == -1) { 3401676Sjpk syslog(LOG_WARNING, 3411676Sjpk "couldn't set SO_RECVUCRED option on transport"); 3421676Sjpk } 3431676Sjpk } 3441676Sjpk 3451676Sjpk /* 3461676Sjpk * Make non global zone nfs4_callback port MLP 3471676Sjpk */ 3481676Sjpk if (use_any && is_system_labeled() && !gzone) { 3491676Sjpk if (anonmlp(fd) == -1) { 3501676Sjpk /* 3511676Sjpk * failing to set this option means nfs4_callback 3521676Sjpk * could fail silently later. So fail it with 3531676Sjpk * with an error message now. 3541676Sjpk */ 3551676Sjpk syslog(LOG_ERR, 3561676Sjpk "couldn't set SO_ANON_MLP option on transport"); 3571676Sjpk (void) t_close(fd); 3581676Sjpk return (-1); 3591676Sjpk } 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_CLTS) 3630Sstevel@tonic-gate tb.qlen = 0; 3640Sstevel@tonic-gate else 3650Sstevel@tonic-gate tb.qlen = backlog; 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate /* LINTED pointer alignment */ 3680Sstevel@tonic-gate ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL); 3690Sstevel@tonic-gate if (ntb == (struct t_bind *)NULL) { 3700Sstevel@tonic-gate syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno); 3710Sstevel@tonic-gate (void) t_close(fd); 3720Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 3730Sstevel@tonic-gate return (-1); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * XXX - what about the space tb->addr.buf points to? This should 3780Sstevel@tonic-gate * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,) 3790Sstevel@tonic-gate * should't be called with T_ALL. 3800Sstevel@tonic-gate */ 3810Sstevel@tonic-gate if (addrlist) 3820Sstevel@tonic-gate tb.addr = *(addrlist->n_addrs); /* structure copy */ 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate if (t_bind(fd, &tb, ntb) == -1) { 3850Sstevel@tonic-gate syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno); 3860Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND); 3870Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 3880Sstevel@tonic-gate (void) t_close(fd); 3890Sstevel@tonic-gate return (-1); 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate /* make sure we bound to the right address */ 3930Sstevel@tonic-gate if (use_any == FALSE && 3940Sstevel@tonic-gate (tb.addr.len != ntb->addr.len || 3950Sstevel@tonic-gate memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) { 3960Sstevel@tonic-gate syslog(LOG_ERR, "t_bind to wrong address"); 3970Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND); 3980Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 3990Sstevel@tonic-gate (void) t_close(fd); 4000Sstevel@tonic-gate return (-1); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * Call nfs4svc_setport so that the kernel can be 4050Sstevel@tonic-gate * informed what port number the daemon is listing 4060Sstevel@tonic-gate * for incoming connection requests. 4070Sstevel@tonic-gate */ 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS || 4100Sstevel@tonic-gate nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL) 4110Sstevel@tonic-gate (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate *addr = &ntb->addr; 4140Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) { 4170Sstevel@tonic-gate /* 4180Sstevel@tonic-gate * Disable the Nagle algorithm on TCP connections. 4190Sstevel@tonic-gate * Connections accepted from this listener will 4200Sstevel@tonic-gate * inherit the listener options. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate /* LINTED pointer alignment */ 4240Sstevel@tonic-gate opt = (struct opthdr *)reqbuf; 4250Sstevel@tonic-gate opt->level = IPPROTO_TCP; 4260Sstevel@tonic-gate opt->name = TCP_NODELAY; 4270Sstevel@tonic-gate opt->len = sizeof (int); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate /* LINTED pointer alignment */ 4300Sstevel@tonic-gate *(int *)((char *)opt + sizeof (*opt)) = 1; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate req.flags = T_NEGOTIATE; 4330Sstevel@tonic-gate req.opt.len = sizeof (*opt) + opt->len; 4340Sstevel@tonic-gate req.opt.buf = (char *)opt; 4350Sstevel@tonic-gate resp.flags = 0; 4360Sstevel@tonic-gate resp.opt.buf = reqbuf; 4370Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || 4407208Svv149972 resp.flags != T_SUCCESS) { 4410Sstevel@tonic-gate syslog(LOG_ERR, 4420Sstevel@tonic-gate "couldn't set NODELAY option for proto %s: t_errno = %d, %m", 4437208Svv149972 nconf->nc_proto, t_errno); 4440Sstevel@tonic-gate } 445*10004Sdai.ngo@sun.com 446*10004Sdai.ngo@sun.com nfslib_set_sockbuf(fd); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate return (fd); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate static int 453*10004Sdai.ngo@sun.com get_opt(int fd, int level, int name) 454*10004Sdai.ngo@sun.com { 455*10004Sdai.ngo@sun.com struct t_optmgmt req, res; 456*10004Sdai.ngo@sun.com struct { 457*10004Sdai.ngo@sun.com struct opthdr opt; 458*10004Sdai.ngo@sun.com int value; 459*10004Sdai.ngo@sun.com } reqbuf; 460*10004Sdai.ngo@sun.com 461*10004Sdai.ngo@sun.com reqbuf.opt.level = level; 462*10004Sdai.ngo@sun.com reqbuf.opt.name = name; 463*10004Sdai.ngo@sun.com reqbuf.opt.len = sizeof (int); 464*10004Sdai.ngo@sun.com reqbuf.value = 0; 465*10004Sdai.ngo@sun.com 466*10004Sdai.ngo@sun.com req.flags = T_CURRENT; 467*10004Sdai.ngo@sun.com req.opt.len = sizeof (reqbuf); 468*10004Sdai.ngo@sun.com req.opt.buf = (char *)&reqbuf; 469*10004Sdai.ngo@sun.com 470*10004Sdai.ngo@sun.com res.flags = 0; 471*10004Sdai.ngo@sun.com res.opt.buf = (char *)&reqbuf; 472*10004Sdai.ngo@sun.com res.opt.maxlen = sizeof (reqbuf); 473*10004Sdai.ngo@sun.com 474*10004Sdai.ngo@sun.com if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) { 475*10004Sdai.ngo@sun.com t_error("t_optmgmt"); 476*10004Sdai.ngo@sun.com return (-1); 477*10004Sdai.ngo@sun.com } 478*10004Sdai.ngo@sun.com return (reqbuf.value); 479*10004Sdai.ngo@sun.com } 480*10004Sdai.ngo@sun.com 481*10004Sdai.ngo@sun.com static int 4821676Sjpk setopt(int fd, int level, int name, int value) 4830Sstevel@tonic-gate { 4840Sstevel@tonic-gate struct t_optmgmt req, resp; 4851676Sjpk struct { 4861676Sjpk struct opthdr opt; 4871676Sjpk int value; 4881676Sjpk } reqbuf; 4890Sstevel@tonic-gate 4901676Sjpk reqbuf.opt.level = level; 4911676Sjpk reqbuf.opt.name = name; 4921676Sjpk reqbuf.opt.len = sizeof (int); 4930Sstevel@tonic-gate 4941676Sjpk reqbuf.value = value; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate req.flags = T_NEGOTIATE; 4971676Sjpk req.opt.len = sizeof (reqbuf); 4981676Sjpk req.opt.buf = (char *)&reqbuf; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate resp.flags = 0; 5011676Sjpk resp.opt.buf = (char *)&reqbuf; 5020Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 5050Sstevel@tonic-gate t_error("t_optmgmt"); 5060Sstevel@tonic-gate return (-1); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate return (0); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5111676Sjpk static int 5121676Sjpk reuseaddr(int fd) 5131676Sjpk { 5141676Sjpk return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1)); 5151676Sjpk } 5161676Sjpk 5171676Sjpk static int 5181676Sjpk recvucred(int fd) 5191676Sjpk { 5201676Sjpk return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1)); 5211676Sjpk } 5221676Sjpk 5231676Sjpk static int 5241676Sjpk anonmlp(int fd) 5251676Sjpk { 5261676Sjpk return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1)); 5271676Sjpk } 5281676Sjpk 5290Sstevel@tonic-gate void 5300Sstevel@tonic-gate nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf) 5310Sstevel@tonic-gate { 5320Sstevel@tonic-gate int error; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * Save the error code across syslog(), just in case syslog() 5360Sstevel@tonic-gate * gets its own error and, therefore, overwrites errno. 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate error = errno; 5390Sstevel@tonic-gate if (t_errno == TSYSERR) { 5400Sstevel@tonic-gate syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m", 5417208Svv149972 tli_name, fd, nconf->nc_proto); 5420Sstevel@tonic-gate } else { 5430Sstevel@tonic-gate syslog(LOG_ERR, 5447208Svv149972 "%s(file descriptor %d/transport %s) TLI error %d", 5457208Svv149972 tli_name, fd, nconf->nc_proto, t_errno); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate errno = error; 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /* 5510Sstevel@tonic-gate * Called to set up service over a particular transport. 5520Sstevel@tonic-gate */ 5530Sstevel@tonic-gate void 5540Sstevel@tonic-gate do_one(char *provider, NETSELDECL(proto), struct protob *protobp0, 5552712Snn35248 int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap) 5560Sstevel@tonic-gate { 5570Sstevel@tonic-gate register int sock; 5580Sstevel@tonic-gate struct protob *protobp; 5590Sstevel@tonic-gate struct netbuf *retaddr; 5600Sstevel@tonic-gate struct netconfig *retnconf; 5610Sstevel@tonic-gate struct netbuf addrmask; 5620Sstevel@tonic-gate int vers; 5630Sstevel@tonic-gate int err; 5640Sstevel@tonic-gate int l; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate if (provider) 5670Sstevel@tonic-gate sock = bind_to_provider(provider, protobp0->serv, &retaddr, 5687208Svv149972 &retnconf); 5690Sstevel@tonic-gate else 5700Sstevel@tonic-gate sock = bind_to_proto(proto, protobp0->serv, &retaddr, 5717208Svv149972 &retnconf); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate if (sock == -1) { 5740Sstevel@tonic-gate (void) syslog(LOG_ERR, 5750Sstevel@tonic-gate "Cannot establish %s service over %s: transport setup problem.", 5767208Svv149972 protobp0->serv, provider ? provider : proto); 5770Sstevel@tonic-gate return; 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if (set_addrmask(sock, retnconf, &addrmask) < 0) { 5810Sstevel@tonic-gate (void) syslog(LOG_ERR, 5820Sstevel@tonic-gate "Cannot set address mask for %s", retnconf->nc_netid); 5830Sstevel@tonic-gate return; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate /* 5870Sstevel@tonic-gate * Register all versions of the programs in the protocol block list. 5880Sstevel@tonic-gate */ 5890Sstevel@tonic-gate l = strlen(NC_UDP); 5900Sstevel@tonic-gate for (protobp = protobp0; protobp; protobp = protobp->next) { 5910Sstevel@tonic-gate for (vers = protobp->versmin; vers <= protobp->versmax; 5927208Svv149972 vers++) { 5930Sstevel@tonic-gate if ((protobp->program == NFS_PROGRAM || 5947208Svv149972 protobp->program == NFS_ACL_PROGRAM) && 5957208Svv149972 vers == NFS_V4 && 5967208Svv149972 strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0) 5970Sstevel@tonic-gate continue; 5980Sstevel@tonic-gate 5992712Snn35248 if (use_pmap) { 6002712Snn35248 /* 6012712Snn35248 * Note that if we're using a portmapper 6022712Snn35248 * instead of rpcbind then we can't do an 6032712Snn35248 * unregister operation here. 6042712Snn35248 * 6052712Snn35248 * The reason is that the portmapper unset 6062712Snn35248 * operation removes all the entries for a 6072712Snn35248 * given program/version regardelss of 6082712Snn35248 * transport protocol. 6092712Snn35248 * 6102712Snn35248 * The caller of this routine needs to ensure 6112712Snn35248 * that __pmap_unset() has been called for all 6122712Snn35248 * program/version service pairs they plan 6132712Snn35248 * to support before they start registering 6142712Snn35248 * each program/version/protocol triplet. 6152712Snn35248 */ 6162712Snn35248 (void) __pmap_set(protobp->program, vers, 6172712Snn35248 retnconf, retaddr); 6182712Snn35248 } else { 6192712Snn35248 (void) rpcb_unset(protobp->program, vers, 6202712Snn35248 retnconf); 6212712Snn35248 (void) rpcb_set(protobp->program, vers, 6222712Snn35248 retnconf, retaddr); 6232712Snn35248 } 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate if (retnconf->nc_semantics == NC_TPI_CLTS) { 6280Sstevel@tonic-gate /* Don't drop core if supporting module(s) aren't loaded. */ 6290Sstevel@tonic-gate (void) signal(SIGSYS, SIG_IGN); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* 6320Sstevel@tonic-gate * svc() doesn't block, it returns success or failure. 6330Sstevel@tonic-gate */ 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate if (svc == NULL && Mysvc4 != NULL) 6360Sstevel@tonic-gate err = (*Mysvc4)(sock, &addrmask, retnconf, 6377208Svv149972 NFS4_SETPORT|NFS4_KRPC_START, retaddr); 6380Sstevel@tonic-gate else 6390Sstevel@tonic-gate err = (*svc)(sock, addrmask, retnconf); 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate if (err < 0) { 6420Sstevel@tonic-gate (void) syslog(LOG_ERR, 6437208Svv149972 "Cannot establish %s service over <file desc." 6447208Svv149972 " %d, protocol %s> : %m. Exiting", 6457208Svv149972 protobp0->serv, sock, retnconf->nc_proto); 6460Sstevel@tonic-gate exit(1); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate /* 6510Sstevel@tonic-gate * We successfully set up the server over this transport. 6520Sstevel@tonic-gate * Add this descriptor to the one being polled on. 6530Sstevel@tonic-gate */ 6540Sstevel@tonic-gate add_to_poll_list(sock, retnconf); 6550Sstevel@tonic-gate } 656*10004Sdai.ngo@sun.com 6570Sstevel@tonic-gate /* 6580Sstevel@tonic-gate * Set up the NFS service over all the available transports. 6590Sstevel@tonic-gate * Returns -1 for failure, 0 for success. 6600Sstevel@tonic-gate */ 6610Sstevel@tonic-gate int 6620Sstevel@tonic-gate do_all(struct protob *protobp, 6632712Snn35248 int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap) 6640Sstevel@tonic-gate { 6650Sstevel@tonic-gate struct netconfig *nconf; 6660Sstevel@tonic-gate NCONF_HANDLE *nc; 6670Sstevel@tonic-gate int l; 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 6700Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 6710Sstevel@tonic-gate return (-1); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate l = strlen(NC_UDP); 6740Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 6750Sstevel@tonic-gate if ((nconf->nc_flag & NC_VISIBLE) && 6760Sstevel@tonic-gate strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 && 6770Sstevel@tonic-gate OK_TPI_TYPE(nconf) && 6780Sstevel@tonic-gate (protobp->program != NFS4_CALLBACK || 6790Sstevel@tonic-gate strncasecmp(nconf->nc_proto, NC_UDP, l) != 0)) 6800Sstevel@tonic-gate do_one(nconf->nc_device, nconf->nc_proto, 6817208Svv149972 protobp, svc, use_pmap); 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate (void) endnetconfig(nc); 6840Sstevel@tonic-gate return (0); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* 6880Sstevel@tonic-gate * poll on the open transport descriptors for events and errors. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate void 6910Sstevel@tonic-gate poll_for_action(void) 6920Sstevel@tonic-gate { 6930Sstevel@tonic-gate int nfds; 6940Sstevel@tonic-gate int i; 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate /* 6970Sstevel@tonic-gate * Keep polling until all transports have been closed. When this 6980Sstevel@tonic-gate * happens, we return. 6990Sstevel@tonic-gate */ 7000Sstevel@tonic-gate while ((int)num_fds > 0) { 7010Sstevel@tonic-gate nfds = poll(poll_array, num_fds, INFTIM); 7020Sstevel@tonic-gate switch (nfds) { 7030Sstevel@tonic-gate case 0: 7040Sstevel@tonic-gate continue; 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate case -1: 7070Sstevel@tonic-gate /* 7080Sstevel@tonic-gate * Some errors from poll could be 7090Sstevel@tonic-gate * due to temporary conditions, and we try to 7100Sstevel@tonic-gate * be robust in the face of them. Other 7110Sstevel@tonic-gate * errors (should never happen in theory) 7120Sstevel@tonic-gate * are fatal (eg. EINVAL, EFAULT). 7130Sstevel@tonic-gate */ 7140Sstevel@tonic-gate switch (errno) { 7150Sstevel@tonic-gate case EINTR: 7167208Svv149972 continue; 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate case EAGAIN: 7190Sstevel@tonic-gate case ENOMEM: 7200Sstevel@tonic-gate (void) sleep(10); 7210Sstevel@tonic-gate continue; 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate default: 7240Sstevel@tonic-gate (void) syslog(LOG_ERR, 7257208Svv149972 "poll failed: %m. Exiting"); 7260Sstevel@tonic-gate exit(1); 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate default: 7290Sstevel@tonic-gate break; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * Go through the poll list looking for events. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate for (i = 0; i < num_fds && nfds > 0; i++) { 7360Sstevel@tonic-gate if (poll_array[i].revents) { 7370Sstevel@tonic-gate nfds--; 7380Sstevel@tonic-gate /* 7390Sstevel@tonic-gate * We have a message, so try to read it. 7400Sstevel@tonic-gate * Record the error return in errno, 7410Sstevel@tonic-gate * so that syslog(LOG_ERR, "...%m") 7420Sstevel@tonic-gate * dumps the corresponding error string. 7430Sstevel@tonic-gate */ 7440Sstevel@tonic-gate if (conn_polled[i].nc.nc_semantics == 7450Sstevel@tonic-gate NC_TPI_CLTS) { 7460Sstevel@tonic-gate errno = do_poll_clts_action( 7477208Svv149972 poll_array[i].fd, i); 7480Sstevel@tonic-gate } else { 7490Sstevel@tonic-gate errno = do_poll_cots_action( 7507208Svv149972 poll_array[i].fd, i); 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate if (errno == 0) 7540Sstevel@tonic-gate continue; 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * Most returned error codes mean that there is 7570Sstevel@tonic-gate * fatal condition which we can only deal with 7580Sstevel@tonic-gate * by closing the transport. 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate if (errno != EAGAIN && errno != ENOMEM) { 7610Sstevel@tonic-gate (void) syslog(LOG_ERR, 7620Sstevel@tonic-gate "Error (%m) reading descriptor %d/transport %s. Closing it.", 7637208Svv149972 poll_array[i].fd, 7647208Svv149972 conn_polled[i].nc.nc_proto); 7650Sstevel@tonic-gate (void) t_close(poll_array[i].fd); 7660Sstevel@tonic-gate remove_from_poll_list(poll_array[i].fd); 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate } else if (errno == ENOMEM) 7690Sstevel@tonic-gate (void) sleep(5); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate (void) syslog(LOG_ERR, 7757208Svv149972 "All transports have been closed with errors. Exiting."); 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * Allocate poll/transport array entries for this descriptor. 7800Sstevel@tonic-gate */ 7810Sstevel@tonic-gate static void 7820Sstevel@tonic-gate add_to_poll_list(int fd, struct netconfig *nconf) 7830Sstevel@tonic-gate { 7840Sstevel@tonic-gate static int poll_array_size = 0; 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate /* 7870Sstevel@tonic-gate * If the arrays are full, allocate new ones. 7880Sstevel@tonic-gate */ 7890Sstevel@tonic-gate if (num_fds == poll_array_size) { 7900Sstevel@tonic-gate struct pollfd *tpa; 7910Sstevel@tonic-gate struct conn_entry *tnp; 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate if (poll_array_size != 0) { 7940Sstevel@tonic-gate tpa = poll_array; 7950Sstevel@tonic-gate tnp = conn_polled; 7960Sstevel@tonic-gate } else 7970Sstevel@tonic-gate tpa = (struct pollfd *)0; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate poll_array_size += POLL_ARRAY_INC_SIZE; 8000Sstevel@tonic-gate /* 8010Sstevel@tonic-gate * Allocate new arrays. 8020Sstevel@tonic-gate */ 8030Sstevel@tonic-gate poll_array = (struct pollfd *) 8040Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct pollfd) + 256); 8050Sstevel@tonic-gate conn_polled = (struct conn_entry *) 8060Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct conn_entry) + 256); 8070Sstevel@tonic-gate if (poll_array == (struct pollfd *)NULL || 8080Sstevel@tonic-gate conn_polled == (struct conn_entry *)NULL) { 8090Sstevel@tonic-gate syslog(LOG_ERR, "malloc failed for poll array"); 8100Sstevel@tonic-gate exit(1); 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate /* 8140Sstevel@tonic-gate * Copy the data of the old ones into new arrays, and 8150Sstevel@tonic-gate * free the old ones. 8160Sstevel@tonic-gate */ 8170Sstevel@tonic-gate if (tpa) { 8180Sstevel@tonic-gate (void) memcpy((void *)poll_array, (void *)tpa, 8197208Svv149972 num_fds * sizeof (struct pollfd)); 8200Sstevel@tonic-gate (void) memcpy((void *)conn_polled, (void *)tnp, 8217208Svv149972 num_fds * sizeof (struct conn_entry)); 8220Sstevel@tonic-gate free((void *)tpa); 8230Sstevel@tonic-gate free((void *)tnp); 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate /* 8280Sstevel@tonic-gate * Set the descriptor and event list. All possible events are 8290Sstevel@tonic-gate * polled for. 8300Sstevel@tonic-gate */ 8310Sstevel@tonic-gate poll_array[num_fds].fd = fd; 8320Sstevel@tonic-gate poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI; 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate /* 8350Sstevel@tonic-gate * Copy the transport data over too. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate conn_polled[num_fds].nc = *nconf; 8380Sstevel@tonic-gate conn_polled[num_fds].closing = 0; 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * Set the descriptor to non-blocking. Avoids a race 8420Sstevel@tonic-gate * between data arriving on the stream and then having it 8430Sstevel@tonic-gate * flushed before we can read it. 8440Sstevel@tonic-gate */ 8450Sstevel@tonic-gate if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 8460Sstevel@tonic-gate (void) syslog(LOG_ERR, 8470Sstevel@tonic-gate "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting", 8487208Svv149972 num_fds, nconf->nc_proto); 8490Sstevel@tonic-gate exit(1); 8500Sstevel@tonic-gate } 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate /* 8530Sstevel@tonic-gate * Count this descriptor. 8540Sstevel@tonic-gate */ 8550Sstevel@tonic-gate ++num_fds; 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate static void 8590Sstevel@tonic-gate remove_from_poll_list(int fd) 8600Sstevel@tonic-gate { 8610Sstevel@tonic-gate int i; 8620Sstevel@tonic-gate int num_to_copy; 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate for (i = 0; i < num_fds; i++) { 8650Sstevel@tonic-gate if (poll_array[i].fd == fd) { 8660Sstevel@tonic-gate --num_fds; 8670Sstevel@tonic-gate num_to_copy = num_fds - i; 8680Sstevel@tonic-gate (void) memcpy((void *)&poll_array[i], 8697208Svv149972 (void *)&poll_array[i+1], 8707208Svv149972 num_to_copy * sizeof (struct pollfd)); 8710Sstevel@tonic-gate (void) memset((void *)&poll_array[num_fds], 0, 8727208Svv149972 sizeof (struct pollfd)); 8730Sstevel@tonic-gate (void) memcpy((void *)&conn_polled[i], 8747208Svv149972 (void *)&conn_polled[i+1], 8757208Svv149972 num_to_copy * sizeof (struct conn_entry)); 8760Sstevel@tonic-gate (void) memset((void *)&conn_polled[num_fds], 0, 8777208Svv149972 sizeof (struct conn_entry)); 8780Sstevel@tonic-gate return; 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list"); 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate /* 8860Sstevel@tonic-gate * Called to read and interpret the event on a connectionless descriptor. 8870Sstevel@tonic-gate * Returns 0 if successful, or a UNIX error code if failure. 8880Sstevel@tonic-gate */ 8890Sstevel@tonic-gate static int 8900Sstevel@tonic-gate do_poll_clts_action(int fd, int conn_index) 8910Sstevel@tonic-gate { 8920Sstevel@tonic-gate int error; 8930Sstevel@tonic-gate int ret; 8940Sstevel@tonic-gate int flags; 8950Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc; 8960Sstevel@tonic-gate static struct t_unitdata *unitdata = NULL; 8970Sstevel@tonic-gate static struct t_uderr *uderr = NULL; 8980Sstevel@tonic-gate static int oldfd = -1; 8990Sstevel@tonic-gate struct nd_hostservlist *host = NULL; 9000Sstevel@tonic-gate struct strbuf ctl[1], data[1]; 9010Sstevel@tonic-gate /* 9020Sstevel@tonic-gate * We just need to have some space to consume the 9030Sstevel@tonic-gate * message in the event we can't use the TLI interface to do the 9040Sstevel@tonic-gate * job. 9050Sstevel@tonic-gate * 9060Sstevel@tonic-gate * We flush the message using getmsg(). For the control part 9070Sstevel@tonic-gate * we allocate enough for any TPI header plus 32 bytes for address 9080Sstevel@tonic-gate * and options. For the data part, there is nothing magic about 9090Sstevel@tonic-gate * the size of the array, but 256 bytes is probably better than 9100Sstevel@tonic-gate * 1 byte, and we don't expect any data portion anyway. 9110Sstevel@tonic-gate * 9120Sstevel@tonic-gate * If the array sizes are too small, we handle this because getmsg() 9130Sstevel@tonic-gate * (called to consume the message) will return MOREDATA|MORECTL. 9140Sstevel@tonic-gate * Thus we just call getmsg() until it's read the message. 9150Sstevel@tonic-gate */ 9160Sstevel@tonic-gate char ctlbuf[sizeof (union T_primitives) + 32]; 9170Sstevel@tonic-gate char databuf[256]; 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate /* 9200Sstevel@tonic-gate * If this is the same descriptor as the last time 9210Sstevel@tonic-gate * do_poll_clts_action was called, we can save some 9220Sstevel@tonic-gate * de-allocation and allocation. 9230Sstevel@tonic-gate */ 9240Sstevel@tonic-gate if (oldfd != fd) { 9250Sstevel@tonic-gate oldfd = fd; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate if (unitdata) { 9280Sstevel@tonic-gate (void) t_free((char *)unitdata, T_UNITDATA); 9290Sstevel@tonic-gate unitdata = NULL; 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate if (uderr) { 9320Sstevel@tonic-gate (void) t_free((char *)uderr, T_UDERROR); 9330Sstevel@tonic-gate uderr = NULL; 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate /* 9380Sstevel@tonic-gate * Allocate a unitdata structure for receiving the event. 9390Sstevel@tonic-gate */ 9400Sstevel@tonic-gate if (unitdata == NULL) { 9410Sstevel@tonic-gate /* LINTED pointer alignment */ 9420Sstevel@tonic-gate unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL); 9430Sstevel@tonic-gate if (unitdata == NULL) { 9440Sstevel@tonic-gate if (t_errno == TSYSERR) { 9450Sstevel@tonic-gate /* 9460Sstevel@tonic-gate * Save the error code across 9470Sstevel@tonic-gate * syslog(), just in case 9480Sstevel@tonic-gate * syslog() gets its own error 9490Sstevel@tonic-gate * and therefore overwrites errno. 9500Sstevel@tonic-gate */ 9510Sstevel@tonic-gate error = errno; 9520Sstevel@tonic-gate (void) syslog(LOG_ERR, 9530Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m", 9547208Svv149972 fd, nconf->nc_proto); 9550Sstevel@tonic-gate return (error); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate (void) syslog(LOG_ERR, 9580Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d", 9597208Svv149972 fd, nconf->nc_proto, t_errno); 9600Sstevel@tonic-gate goto flush_it; 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate try_again: 9650Sstevel@tonic-gate flags = 0; 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate /* 9680Sstevel@tonic-gate * The idea is we wait for T_UNITDATA_IND's. Of course, 9690Sstevel@tonic-gate * we don't get any, because rpcmod filters them out. 9700Sstevel@tonic-gate * However, we need to call t_rcvudata() to let TLI 9710Sstevel@tonic-gate * tell us we have a T_UDERROR_IND. 9720Sstevel@tonic-gate * 9730Sstevel@tonic-gate * algorithm is: 9740Sstevel@tonic-gate * t_rcvudata(), expecting TLOOK. 9750Sstevel@tonic-gate * t_look(), expecting T_UDERR. 9760Sstevel@tonic-gate * t_rcvuderr(), expecting success (0). 9770Sstevel@tonic-gate * expand destination address into ASCII, 9780Sstevel@tonic-gate * and dump it. 9790Sstevel@tonic-gate */ 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate ret = t_rcvudata(fd, unitdata, &flags); 9820Sstevel@tonic-gate if (ret == 0 || t_errno == TBUFOVFLW) { 9830Sstevel@tonic-gate (void) syslog(LOG_WARNING, 9840Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes", 9857208Svv149972 fd, nconf->nc_proto, unitdata->udata.len); 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate /* 9880Sstevel@tonic-gate * Even though we don't expect any data, in case we do, 9890Sstevel@tonic-gate * keep reading until there is no more. 9900Sstevel@tonic-gate */ 9910Sstevel@tonic-gate if (flags & T_MORE) 9920Sstevel@tonic-gate goto try_again; 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate return (0); 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate switch (t_errno) { 9980Sstevel@tonic-gate case TNODATA: 9990Sstevel@tonic-gate return (0); 10000Sstevel@tonic-gate case TSYSERR: 10010Sstevel@tonic-gate /* 10020Sstevel@tonic-gate * System errors are returned to caller. 10030Sstevel@tonic-gate * Save the error code across 10040Sstevel@tonic-gate * syslog(), just in case 10050Sstevel@tonic-gate * syslog() gets its own error 10060Sstevel@tonic-gate * and therefore overwrites errno. 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate error = errno; 10090Sstevel@tonic-gate (void) syslog(LOG_ERR, 10107208Svv149972 "t_rcvudata(file descriptor %d/transport %s) %m", 10117208Svv149972 fd, nconf->nc_proto); 10120Sstevel@tonic-gate return (error); 10130Sstevel@tonic-gate case TLOOK: 10140Sstevel@tonic-gate break; 10150Sstevel@tonic-gate default: 10160Sstevel@tonic-gate (void) syslog(LOG_ERR, 10170Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) TLI error %d", 10187208Svv149972 fd, nconf->nc_proto, t_errno); 10190Sstevel@tonic-gate goto flush_it; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate ret = t_look(fd); 10230Sstevel@tonic-gate switch (ret) { 10240Sstevel@tonic-gate case 0: 10250Sstevel@tonic-gate return (0); 10260Sstevel@tonic-gate case -1: 10270Sstevel@tonic-gate /* 10280Sstevel@tonic-gate * System errors are returned to caller. 10290Sstevel@tonic-gate */ 10300Sstevel@tonic-gate if (t_errno == TSYSERR) { 10310Sstevel@tonic-gate /* 10320Sstevel@tonic-gate * Save the error code across 10330Sstevel@tonic-gate * syslog(), just in case 10340Sstevel@tonic-gate * syslog() gets its own error 10350Sstevel@tonic-gate * and therefore overwrites errno. 10360Sstevel@tonic-gate */ 10370Sstevel@tonic-gate error = errno; 10380Sstevel@tonic-gate (void) syslog(LOG_ERR, 10397208Svv149972 "t_look(file descriptor %d/transport %s) %m", 10407208Svv149972 fd, nconf->nc_proto); 10410Sstevel@tonic-gate return (error); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate (void) syslog(LOG_ERR, 10447208Svv149972 "t_look(file descriptor %d/transport %s) TLI error %d", 10457208Svv149972 fd, nconf->nc_proto, t_errno); 10460Sstevel@tonic-gate goto flush_it; 10470Sstevel@tonic-gate case T_UDERR: 10480Sstevel@tonic-gate break; 10490Sstevel@tonic-gate default: 10500Sstevel@tonic-gate (void) syslog(LOG_WARNING, 10510Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)", 10527208Svv149972 fd, nconf->nc_proto, ret, T_UDERR); 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate if (uderr == NULL) { 10560Sstevel@tonic-gate /* LINTED pointer alignment */ 10570Sstevel@tonic-gate uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL); 10580Sstevel@tonic-gate if (uderr == NULL) { 10590Sstevel@tonic-gate if (t_errno == TSYSERR) { 10600Sstevel@tonic-gate /* 10610Sstevel@tonic-gate * Save the error code across 10620Sstevel@tonic-gate * syslog(), just in case 10630Sstevel@tonic-gate * syslog() gets its own error 10640Sstevel@tonic-gate * and therefore overwrites errno. 10650Sstevel@tonic-gate */ 10660Sstevel@tonic-gate error = errno; 10670Sstevel@tonic-gate (void) syslog(LOG_ERR, 10680Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m", 10697208Svv149972 fd, nconf->nc_proto); 10700Sstevel@tonic-gate return (error); 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate (void) syslog(LOG_ERR, 10730Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d", 10747208Svv149972 fd, nconf->nc_proto, t_errno); 10750Sstevel@tonic-gate goto flush_it; 10760Sstevel@tonic-gate } 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate ret = t_rcvuderr(fd, uderr); 10800Sstevel@tonic-gate if (ret == 0) { 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate /* 10830Sstevel@tonic-gate * Save the datagram error in errno, so that the 10840Sstevel@tonic-gate * %m argument to syslog picks up the error string. 10850Sstevel@tonic-gate */ 10860Sstevel@tonic-gate errno = uderr->error; 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate /* 10890Sstevel@tonic-gate * Log the datagram error, then log the host that 10900Sstevel@tonic-gate * probably triggerred. Cannot log both in the 10910Sstevel@tonic-gate * same transaction because of packet size limitations 10920Sstevel@tonic-gate * in /dev/log. 10930Sstevel@tonic-gate */ 10940Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 10950Sstevel@tonic-gate "NFS response over <file descriptor %d/transport %s> generated error: %m", 10967208Svv149972 fd, nconf->nc_proto); 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate /* 10990Sstevel@tonic-gate * Try to map the client's address back to a 11000Sstevel@tonic-gate * name. 11010Sstevel@tonic-gate */ 11020Sstevel@tonic-gate ret = netdir_getbyaddr(nconf, &host, &uderr->addr); 11030Sstevel@tonic-gate if (ret != -1 && host && host->h_cnt > 0 && 11040Sstevel@tonic-gate host->h_hostservs) { 11050Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 11060Sstevel@tonic-gate "Bad NFS response was sent to client with host name: %s; service port: %s", 11077208Svv149972 host->h_hostservs->h_host, 11087208Svv149972 host->h_hostservs->h_serv); 11090Sstevel@tonic-gate } else { 11100Sstevel@tonic-gate int i, j; 11110Sstevel@tonic-gate char *buf; 11120Sstevel@tonic-gate char *hex = "0123456789abcdef"; 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* 11150Sstevel@tonic-gate * Mapping failed, print the whole thing 11160Sstevel@tonic-gate * in ASCII hex. 11170Sstevel@tonic-gate */ 11180Sstevel@tonic-gate buf = (char *)malloc(uderr->addr.len * 2 + 1); 11190Sstevel@tonic-gate for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) { 11200Sstevel@tonic-gate buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf]; 11210Sstevel@tonic-gate buf[j+1] = hex[uderr->addr.buf[i] & 0xf]; 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate buf[j] = '\0'; 11240Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 11250Sstevel@tonic-gate "Bad NFS response was sent to client with transport address: 0x%s", 11267208Svv149972 buf); 11270Sstevel@tonic-gate free((void *)buf); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate if (ret == 0 && host != NULL) 11310Sstevel@tonic-gate netdir_free((void *)host, ND_HOSTSERVLIST); 11320Sstevel@tonic-gate return (0); 11330Sstevel@tonic-gate } 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate switch (t_errno) { 11360Sstevel@tonic-gate case TNOUDERR: 11370Sstevel@tonic-gate goto flush_it; 11380Sstevel@tonic-gate case TSYSERR: 11390Sstevel@tonic-gate /* 11400Sstevel@tonic-gate * System errors are returned to caller. 11410Sstevel@tonic-gate * Save the error code across 11420Sstevel@tonic-gate * syslog(), just in case 11430Sstevel@tonic-gate * syslog() gets its own error 11440Sstevel@tonic-gate * and therefore overwrites errno. 11450Sstevel@tonic-gate */ 11460Sstevel@tonic-gate error = errno; 11470Sstevel@tonic-gate (void) syslog(LOG_ERR, 11487208Svv149972 "t_rcvuderr(file descriptor %d/transport %s) %m", 11497208Svv149972 fd, nconf->nc_proto); 11500Sstevel@tonic-gate return (error); 11510Sstevel@tonic-gate default: 11520Sstevel@tonic-gate (void) syslog(LOG_ERR, 11530Sstevel@tonic-gate "t_rcvuderr(file descriptor %d/transport %s) TLI error %d", 11547208Svv149972 fd, nconf->nc_proto, t_errno); 11550Sstevel@tonic-gate goto flush_it; 11560Sstevel@tonic-gate } 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate flush_it: 11590Sstevel@tonic-gate /* 11600Sstevel@tonic-gate * If we get here, then we could not cope with whatever message 11610Sstevel@tonic-gate * we attempted to read, so flush it. If we did read a message, 11620Sstevel@tonic-gate * and one isn't present, that is all right, because fd is in 11630Sstevel@tonic-gate * nonblocking mode. 11640Sstevel@tonic-gate */ 11650Sstevel@tonic-gate (void) syslog(LOG_ERR, 11660Sstevel@tonic-gate "Flushing one input message from <file descriptor %d/transport %s>", 11677208Svv149972 fd, nconf->nc_proto); 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate /* 11700Sstevel@tonic-gate * Read and discard the message. Do this this until there is 11710Sstevel@tonic-gate * no more control/data in the message or until we get an error. 11720Sstevel@tonic-gate */ 11730Sstevel@tonic-gate do { 11740Sstevel@tonic-gate ctl->maxlen = sizeof (ctlbuf); 11750Sstevel@tonic-gate ctl->buf = ctlbuf; 11760Sstevel@tonic-gate data->maxlen = sizeof (databuf); 11770Sstevel@tonic-gate data->buf = databuf; 11780Sstevel@tonic-gate flags = 0; 11790Sstevel@tonic-gate ret = getmsg(fd, ctl, data, &flags); 11800Sstevel@tonic-gate if (ret == -1) 11810Sstevel@tonic-gate return (errno); 11820Sstevel@tonic-gate } while (ret != 0); 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate return (0); 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate static void 11880Sstevel@tonic-gate conn_close_oldest(void) 11890Sstevel@tonic-gate { 11900Sstevel@tonic-gate int fd; 11910Sstevel@tonic-gate int i1; 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate /* 11940Sstevel@tonic-gate * Find the oldest connection that is not already in the 11950Sstevel@tonic-gate * process of shutting down. 11960Sstevel@tonic-gate */ 11970Sstevel@tonic-gate for (i1 = end_listen_fds; /* no conditional expression */; i1++) { 11980Sstevel@tonic-gate if (i1 >= num_fds) 11990Sstevel@tonic-gate return; 12000Sstevel@tonic-gate if (conn_polled[i1].closing == 0) 12010Sstevel@tonic-gate break; 12020Sstevel@tonic-gate } 12030Sstevel@tonic-gate #ifdef DEBUG 12040Sstevel@tonic-gate printf("too many connections (%d), releasing oldest (%d)\n", 12057208Svv149972 num_conns, poll_array[i1].fd); 12060Sstevel@tonic-gate #else 12070Sstevel@tonic-gate syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)", 12087208Svv149972 num_conns, poll_array[i1].fd); 12090Sstevel@tonic-gate #endif 12100Sstevel@tonic-gate fd = poll_array[i1].fd; 12110Sstevel@tonic-gate if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) { 12120Sstevel@tonic-gate /* 12130Sstevel@tonic-gate * For politeness, send a T_DISCON_REQ to the transport 12140Sstevel@tonic-gate * provider. We close the stream anyway. 12150Sstevel@tonic-gate */ 12160Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0); 12170Sstevel@tonic-gate num_conns--; 12180Sstevel@tonic-gate remove_from_poll_list(fd); 12190Sstevel@tonic-gate (void) t_close(fd); 12200Sstevel@tonic-gate } else { 12210Sstevel@tonic-gate /* 12220Sstevel@tonic-gate * For orderly release, we do not close the stream 12230Sstevel@tonic-gate * until the T_ORDREL_IND arrives to complete 12240Sstevel@tonic-gate * the handshake. 12250Sstevel@tonic-gate */ 12260Sstevel@tonic-gate if (t_sndrel(fd) == 0) 12270Sstevel@tonic-gate conn_polled[i1].closing = 1; 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate static boolean_t 12320Sstevel@tonic-gate conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 12330Sstevel@tonic-gate { 12340Sstevel@tonic-gate struct conn_ind *conn; 12350Sstevel@tonic-gate struct conn_ind *next_conn; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate conn = (struct conn_ind *)malloc(sizeof (*conn)); 12380Sstevel@tonic-gate if (conn == NULL) { 12390Sstevel@tonic-gate syslog(LOG_ERR, "malloc for listen indication failed"); 12400Sstevel@tonic-gate return (FALSE); 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate /* LINTED pointer alignment */ 12440Sstevel@tonic-gate conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); 12450Sstevel@tonic-gate if (conn->conn_call == NULL) { 12460Sstevel@tonic-gate free((char *)conn); 12470Sstevel@tonic-gate nfslib_log_tli_error("t_alloc", fd, nconf); 12480Sstevel@tonic-gate return (FALSE); 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate if (t_listen(fd, conn->conn_call) == -1) { 12520Sstevel@tonic-gate nfslib_log_tli_error("t_listen", fd, nconf); 12530Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL); 12540Sstevel@tonic-gate free((char *)conn); 12550Sstevel@tonic-gate return (FALSE); 12560Sstevel@tonic-gate } 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate if (conn->conn_call->udata.len > 0) { 12590Sstevel@tonic-gate syslog(LOG_WARNING, 12600Sstevel@tonic-gate "rejecting inbound connection(%s) with %d bytes of connect data", 12617208Svv149972 nconf->nc_proto, conn->conn_call->udata.len); 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate conn->conn_call->udata.len = 0; 12640Sstevel@tonic-gate (void) t_snddis(fd, conn->conn_call); 12650Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL); 12660Sstevel@tonic-gate free((char *)conn); 12670Sstevel@tonic-gate return (FALSE); 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate if ((next_conn = *connp) != NULL) { 12710Sstevel@tonic-gate next_conn->conn_prev->conn_next = conn; 12720Sstevel@tonic-gate conn->conn_next = next_conn; 12730Sstevel@tonic-gate conn->conn_prev = next_conn->conn_prev; 12740Sstevel@tonic-gate next_conn->conn_prev = conn; 12750Sstevel@tonic-gate } else { 12760Sstevel@tonic-gate conn->conn_next = conn; 12770Sstevel@tonic-gate conn->conn_prev = conn; 12780Sstevel@tonic-gate *connp = conn; 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate return (TRUE); 12810Sstevel@tonic-gate } 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate static int 12840Sstevel@tonic-gate discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 12850Sstevel@tonic-gate { 12860Sstevel@tonic-gate struct conn_ind *conn; 12870Sstevel@tonic-gate struct t_discon discon; 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate discon.udata.buf = (char *)0; 12900Sstevel@tonic-gate discon.udata.maxlen = 0; 12910Sstevel@tonic-gate if (t_rcvdis(fd, &discon) == -1) { 12920Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf); 12930Sstevel@tonic-gate return (-1); 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate conn = *connp; 12970Sstevel@tonic-gate if (conn == NULL) 12980Sstevel@tonic-gate return (0); 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate do { 13010Sstevel@tonic-gate if (conn->conn_call->sequence == discon.sequence) { 13020Sstevel@tonic-gate if (conn->conn_next == conn) 13030Sstevel@tonic-gate *connp = (struct conn_ind *)0; 13040Sstevel@tonic-gate else { 13050Sstevel@tonic-gate if (conn == *connp) { 13060Sstevel@tonic-gate *connp = conn->conn_next; 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate conn->conn_next->conn_prev = conn->conn_prev; 13090Sstevel@tonic-gate conn->conn_prev->conn_next = conn->conn_next; 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate free((char *)conn); 13120Sstevel@tonic-gate break; 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate conn = conn->conn_next; 13150Sstevel@tonic-gate } while (conn != *connp); 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate return (0); 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate static void 13210Sstevel@tonic-gate cots_listen_event(int fd, int conn_index) 13220Sstevel@tonic-gate { 13230Sstevel@tonic-gate struct t_call *call; 13240Sstevel@tonic-gate struct conn_ind *conn; 13250Sstevel@tonic-gate struct conn_ind *conn_head; 13260Sstevel@tonic-gate int event; 13270Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc; 13280Sstevel@tonic-gate int new_fd; 13290Sstevel@tonic-gate struct netbuf addrmask; 13300Sstevel@tonic-gate int ret = 0; 13310Sstevel@tonic-gate char *clnt; 13320Sstevel@tonic-gate char *clnt_uaddr = NULL; 13330Sstevel@tonic-gate struct nd_hostservlist *clnt_serv = NULL; 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate conn_head = (struct conn_ind *)0; 13360Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head); 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate while ((conn = conn_head) != NULL) { 13390Sstevel@tonic-gate conn_head = conn->conn_next; 13400Sstevel@tonic-gate if (conn_head == conn) 13410Sstevel@tonic-gate conn_head = (struct conn_ind *)0; 13420Sstevel@tonic-gate else { 13430Sstevel@tonic-gate conn_head->conn_prev = conn->conn_prev; 13440Sstevel@tonic-gate conn->conn_prev->conn_next = conn_head; 13450Sstevel@tonic-gate } 13460Sstevel@tonic-gate call = conn->conn_call; 13470Sstevel@tonic-gate free((char *)conn); 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate /* 13500Sstevel@tonic-gate * If we have already accepted the maximum number of 13510Sstevel@tonic-gate * connections allowed on the command line, then drop 13520Sstevel@tonic-gate * the oldest connection (for any protocol) before 13530Sstevel@tonic-gate * accepting the new connection. Unless explicitly 13540Sstevel@tonic-gate * set on the command line, max_conns_allowed is -1. 13550Sstevel@tonic-gate */ 13560Sstevel@tonic-gate if (max_conns_allowed != -1 && num_conns >= max_conns_allowed) 13570Sstevel@tonic-gate conn_close_oldest(); 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate /* 13600Sstevel@tonic-gate * Create a new transport endpoint for the same proto as 13610Sstevel@tonic-gate * the listener. 13620Sstevel@tonic-gate */ 13630Sstevel@tonic-gate new_fd = nfslib_transport_open(nconf); 13640Sstevel@tonic-gate if (new_fd == -1) { 13650Sstevel@tonic-gate call->udata.len = 0; 13660Sstevel@tonic-gate (void) t_snddis(fd, call); 13670Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 13680Sstevel@tonic-gate syslog(LOG_ERR, "Cannot establish transport over %s", 13697208Svv149972 nconf->nc_device); 13700Sstevel@tonic-gate continue; 13710Sstevel@tonic-gate } 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate /* Bind to a generic address/port for the accepting stream. */ 13740Sstevel@tonic-gate if (t_bind(new_fd, (struct t_bind *)NULL, 13750Sstevel@tonic-gate (struct t_bind *)NULL) == -1) { 13760Sstevel@tonic-gate nfslib_log_tli_error("t_bind", new_fd, nconf); 13770Sstevel@tonic-gate call->udata.len = 0; 13780Sstevel@tonic-gate (void) t_snddis(fd, call); 13790Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 13800Sstevel@tonic-gate (void) t_close(new_fd); 13810Sstevel@tonic-gate continue; 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate while (t_accept(fd, new_fd, call) == -1) { 13850Sstevel@tonic-gate if (t_errno != TLOOK) { 13860Sstevel@tonic-gate #ifdef DEBUG 13870Sstevel@tonic-gate nfslib_log_tli_error("t_accept", fd, nconf); 13880Sstevel@tonic-gate #endif 13890Sstevel@tonic-gate call->udata.len = 0; 13900Sstevel@tonic-gate (void) t_snddis(fd, call); 13910Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 13920Sstevel@tonic-gate (void) t_close(new_fd); 13930Sstevel@tonic-gate goto do_next_conn; 13940Sstevel@tonic-gate } 13950Sstevel@tonic-gate while (event = t_look(fd)) { 13960Sstevel@tonic-gate switch (event) { 13970Sstevel@tonic-gate case T_LISTEN: 13980Sstevel@tonic-gate #ifdef DEBUG 13990Sstevel@tonic-gate printf( 14000Sstevel@tonic-gate "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto); 14010Sstevel@tonic-gate #endif 14020Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head); 14030Sstevel@tonic-gate continue; 14040Sstevel@tonic-gate case T_DISCONNECT: 14050Sstevel@tonic-gate #ifdef DEBUG 14060Sstevel@tonic-gate printf( 14070Sstevel@tonic-gate "cots_listen_event(%s): T_DISCONNECT during accept processing\n", 14087208Svv149972 nconf->nc_proto); 14090Sstevel@tonic-gate #endif 14100Sstevel@tonic-gate (void) discon_get(fd, nconf, 14117208Svv149972 &conn_head); 14120Sstevel@tonic-gate continue; 14130Sstevel@tonic-gate default: 14140Sstevel@tonic-gate syslog(LOG_ERR, 14150Sstevel@tonic-gate "unexpected event 0x%x during accept processing (%s)", 14167208Svv149972 event, nconf->nc_proto); 14170Sstevel@tonic-gate call->udata.len = 0; 14180Sstevel@tonic-gate (void) t_snddis(fd, call); 14190Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 14200Sstevel@tonic-gate (void) t_close(new_fd); 14210Sstevel@tonic-gate goto do_next_conn; 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate if (set_addrmask(new_fd, nconf, &addrmask) < 0) { 14270Sstevel@tonic-gate (void) syslog(LOG_ERR, 14280Sstevel@tonic-gate "Cannot set address mask for %s", 14297208Svv149972 nconf->nc_netid); 14300Sstevel@tonic-gate return; 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate /* Tell KRPC about the new stream. */ 14340Sstevel@tonic-gate if (Mysvc4 != NULL) 14350Sstevel@tonic-gate ret = (*Mysvc4)(new_fd, &addrmask, nconf, 14367208Svv149972 NFS4_KRPC_START, &call->addr); 14370Sstevel@tonic-gate else 14380Sstevel@tonic-gate ret = (*Mysvc)(new_fd, addrmask, nconf); 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate if (ret < 0) { 14410Sstevel@tonic-gate if (errno != ENOTCONN) { 14420Sstevel@tonic-gate syslog(LOG_ERR, 14430Sstevel@tonic-gate "unable to register new connection: %m"); 14440Sstevel@tonic-gate } else { 14450Sstevel@tonic-gate /* 14460Sstevel@tonic-gate * This is the only error that could be 14470Sstevel@tonic-gate * caused by the client, so who was it? 14480Sstevel@tonic-gate */ 14490Sstevel@tonic-gate if (netdir_getbyaddr(nconf, &clnt_serv, 14500Sstevel@tonic-gate &(call->addr)) == ND_OK && 14510Sstevel@tonic-gate clnt_serv->h_cnt > 0) 14520Sstevel@tonic-gate clnt = clnt_serv->h_hostservs->h_host; 14530Sstevel@tonic-gate else 14540Sstevel@tonic-gate clnt = clnt_uaddr = taddr2uaddr(nconf, 14550Sstevel@tonic-gate &(call->addr)); 14560Sstevel@tonic-gate /* 14570Sstevel@tonic-gate * If we don't know who the client was, 14580Sstevel@tonic-gate * remain silent. 14590Sstevel@tonic-gate */ 14600Sstevel@tonic-gate if (clnt) 14610Sstevel@tonic-gate syslog(LOG_ERR, 14620Sstevel@tonic-gate "unable to register new connection: client %s has dropped connection", clnt); 14630Sstevel@tonic-gate if (clnt_serv) 14640Sstevel@tonic-gate netdir_free(clnt_serv, ND_HOSTSERVLIST); 14650Sstevel@tonic-gate if (clnt_uaddr) 14660Sstevel@tonic-gate free(clnt_uaddr); 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate free(addrmask.buf); 14690Sstevel@tonic-gate (void) t_snddis(new_fd, (struct t_call *)0); 14700Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 14710Sstevel@tonic-gate (void) t_close(new_fd); 14720Sstevel@tonic-gate goto do_next_conn; 14730Sstevel@tonic-gate } 14740Sstevel@tonic-gate 14750Sstevel@tonic-gate free(addrmask.buf); 14760Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate /* 14790Sstevel@tonic-gate * Poll on the new descriptor so that we get disconnect 14800Sstevel@tonic-gate * and orderly release indications. 14810Sstevel@tonic-gate */ 14820Sstevel@tonic-gate num_conns++; 14830Sstevel@tonic-gate add_to_poll_list(new_fd, nconf); 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate /* Reset nconf in case it has been moved. */ 14860Sstevel@tonic-gate nconf = &conn_polled[conn_index].nc; 14870Sstevel@tonic-gate do_next_conn:; 14880Sstevel@tonic-gate } 14890Sstevel@tonic-gate } 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate static int 14920Sstevel@tonic-gate do_poll_cots_action(int fd, int conn_index) 14930Sstevel@tonic-gate { 14940Sstevel@tonic-gate char buf[256]; 14950Sstevel@tonic-gate int event; 14960Sstevel@tonic-gate int i1; 14970Sstevel@tonic-gate int flags; 14980Sstevel@tonic-gate struct conn_entry *connent = &conn_polled[conn_index]; 14990Sstevel@tonic-gate struct netconfig *nconf = &(connent->nc); 15000Sstevel@tonic-gate const char *errorstr; 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate while (event = t_look(fd)) { 15030Sstevel@tonic-gate switch (event) { 15040Sstevel@tonic-gate case T_LISTEN: 15050Sstevel@tonic-gate #ifdef DEBUG 15060Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd); 15070Sstevel@tonic-gate #endif 15080Sstevel@tonic-gate cots_listen_event(fd, conn_index); 15090Sstevel@tonic-gate break; 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate case T_DATA: 15120Sstevel@tonic-gate #ifdef DEBUG 15130Sstevel@tonic-gate printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto); 15140Sstevel@tonic-gate #endif 15150Sstevel@tonic-gate /* 15160Sstevel@tonic-gate * Receive a private notification from CONS rpcmod. 15170Sstevel@tonic-gate */ 15180Sstevel@tonic-gate i1 = t_rcv(fd, buf, sizeof (buf), &flags); 15190Sstevel@tonic-gate if (i1 == -1) { 15200Sstevel@tonic-gate syslog(LOG_ERR, "t_rcv failed"); 15210Sstevel@tonic-gate break; 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate if (i1 < sizeof (int)) 15240Sstevel@tonic-gate break; 15250Sstevel@tonic-gate i1 = BE32_TO_U32(buf); 15260Sstevel@tonic-gate if (i1 == 1 || i1 == 2) { 15270Sstevel@tonic-gate /* 15280Sstevel@tonic-gate * This connection has been idle for too long, 15290Sstevel@tonic-gate * so release it as politely as we can. If we 15300Sstevel@tonic-gate * have already initiated an orderly release 15310Sstevel@tonic-gate * and we get notified that the stream is 15320Sstevel@tonic-gate * still idle, pull the plug. This prevents 15330Sstevel@tonic-gate * hung connections from continuing to consume 15340Sstevel@tonic-gate * resources. 15350Sstevel@tonic-gate */ 15360Sstevel@tonic-gate #ifdef DEBUG 15370Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd); 15380Sstevel@tonic-gate printf("initiating orderly release of idle connection\n"); 15390Sstevel@tonic-gate #endif 15400Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_COTS || 15417208Svv149972 connent->closing != 0) { 15420Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0); 15430Sstevel@tonic-gate goto fdclose; 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate /* 15460Sstevel@tonic-gate * For NC_TPI_COTS_ORD, the stream is closed 15470Sstevel@tonic-gate * and removed from the poll list when the 15480Sstevel@tonic-gate * T_ORDREL is received from the provider. We 15490Sstevel@tonic-gate * don't wait for it here because it may take 15500Sstevel@tonic-gate * a while for the transport to shut down. 15510Sstevel@tonic-gate */ 15520Sstevel@tonic-gate if (t_sndrel(fd) == -1) { 15530Sstevel@tonic-gate syslog(LOG_ERR, 15540Sstevel@tonic-gate "unable to send orderly release %m"); 15550Sstevel@tonic-gate } 15560Sstevel@tonic-gate connent->closing = 1; 15570Sstevel@tonic-gate } else 15580Sstevel@tonic-gate syslog(LOG_ERR, 15590Sstevel@tonic-gate "unexpected event from CONS rpcmod %d", i1); 15600Sstevel@tonic-gate break; 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate case T_ORDREL: 15630Sstevel@tonic-gate #ifdef DEBUG 15640Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd); 15650Sstevel@tonic-gate #endif 15660Sstevel@tonic-gate /* Perform an orderly release. */ 15670Sstevel@tonic-gate if (t_rcvrel(fd) == 0) { 15680Sstevel@tonic-gate /* T_ORDREL on listen fd's should be ignored */ 15690Sstevel@tonic-gate if (!is_listen_fd_index(conn_index)) { 15700Sstevel@tonic-gate (void) t_sndrel(fd); 15710Sstevel@tonic-gate goto fdclose; 15720Sstevel@tonic-gate } 15730Sstevel@tonic-gate break; 15740Sstevel@tonic-gate 15750Sstevel@tonic-gate } else if (t_errno == TLOOK) { 15760Sstevel@tonic-gate break; 15770Sstevel@tonic-gate } else { 15780Sstevel@tonic-gate nfslib_log_tli_error("t_rcvrel", fd, nconf); 15790Sstevel@tonic-gate 15800Sstevel@tonic-gate /* 15810Sstevel@tonic-gate * check to make sure we do not close 15820Sstevel@tonic-gate * listen fd 15830Sstevel@tonic-gate */ 15840Sstevel@tonic-gate if (is_listen_fd_index(conn_index)) 15850Sstevel@tonic-gate break; 15860Sstevel@tonic-gate else 15870Sstevel@tonic-gate goto fdclose; 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate case T_DISCONNECT: 15910Sstevel@tonic-gate #ifdef DEBUG 15920Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd); 15930Sstevel@tonic-gate #endif 15940Sstevel@tonic-gate if (t_rcvdis(fd, (struct t_discon *)NULL) == -1) 15950Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf); 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate /* 15980Sstevel@tonic-gate * T_DISCONNECT on listen fd's should be ignored. 15990Sstevel@tonic-gate */ 16000Sstevel@tonic-gate if (is_listen_fd_index(conn_index)) 16010Sstevel@tonic-gate break; 16020Sstevel@tonic-gate else 16030Sstevel@tonic-gate goto fdclose; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate case T_ERROR: 16060Sstevel@tonic-gate default: 16070Sstevel@tonic-gate if (event == T_ERROR || t_errno == TSYSERR) { 16087208Svv149972 if ((errorstr = strerror(errno)) == NULL) { 16097208Svv149972 (void) sprintf(buf, 16107208Svv149972 "Unknown error num %d", errno); 16117208Svv149972 errorstr = (const char *) buf; 16127208Svv149972 } 16130Sstevel@tonic-gate } else if (event == -1) 16140Sstevel@tonic-gate errorstr = t_strerror(t_errno); 16150Sstevel@tonic-gate else 16160Sstevel@tonic-gate errorstr = ""; 16170Sstevel@tonic-gate syslog(LOG_ERR, 16180Sstevel@tonic-gate "unexpected TLI event (0x%x) on " 16190Sstevel@tonic-gate "connection-oriented transport(%s,%d):%s", 16200Sstevel@tonic-gate event, nconf->nc_proto, fd, errorstr); 16210Sstevel@tonic-gate fdclose: 16220Sstevel@tonic-gate num_conns--; 16230Sstevel@tonic-gate remove_from_poll_list(fd); 16240Sstevel@tonic-gate (void) t_close(fd); 16250Sstevel@tonic-gate return (0); 16260Sstevel@tonic-gate } 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate return (0); 16300Sstevel@tonic-gate } 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate static char * 16330Sstevel@tonic-gate serv_name_to_port_name(char *name) 16340Sstevel@tonic-gate { 16350Sstevel@tonic-gate /* 16360Sstevel@tonic-gate * Map service names (used primarily in logging) to 16370Sstevel@tonic-gate * RPC port names (used by netdir_*() routines). 16380Sstevel@tonic-gate */ 16390Sstevel@tonic-gate if (strcmp(name, "NFS") == 0) { 16400Sstevel@tonic-gate return ("nfs"); 16410Sstevel@tonic-gate } else if (strcmp(name, "NLM") == 0) { 16420Sstevel@tonic-gate return ("lockd"); 16430Sstevel@tonic-gate } else if (strcmp(name, "NFS4_CALLBACK") == 0) { 16440Sstevel@tonic-gate return ("nfs4_callback"); 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate return ("unrecognized"); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate static int 16510Sstevel@tonic-gate bind_to_provider(char *provider, char *serv, struct netbuf **addr, 16520Sstevel@tonic-gate struct netconfig **retnconf) 16530Sstevel@tonic-gate { 16540Sstevel@tonic-gate struct netconfig *nconf; 16550Sstevel@tonic-gate NCONF_HANDLE *nc; 16560Sstevel@tonic-gate struct nd_hostserv hs; 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate hs.h_host = HOST_SELF; 16590Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv); 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 16620Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 16630Sstevel@tonic-gate return (-1); 16640Sstevel@tonic-gate } 16650Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 16660Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) && 16670Sstevel@tonic-gate strcmp(nconf->nc_device, provider) == 0) { 16680Sstevel@tonic-gate *retnconf = nconf; 16690Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs, 16707208Svv149972 listen_backlog)); 16710Sstevel@tonic-gate } 16720Sstevel@tonic-gate } 16730Sstevel@tonic-gate (void) endnetconfig(nc); 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for provider %s", 16760Sstevel@tonic-gate provider); 16770Sstevel@tonic-gate return (-1); 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate static int 16810Sstevel@tonic-gate bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr, 16820Sstevel@tonic-gate struct netconfig **retnconf) 16830Sstevel@tonic-gate { 16840Sstevel@tonic-gate struct netconfig *nconf; 16850Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 16860Sstevel@tonic-gate struct nd_hostserv hs; 16870Sstevel@tonic-gate 16880Sstevel@tonic-gate hs.h_host = HOST_SELF; 16890Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv); 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 16920Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 16930Sstevel@tonic-gate return (-1); 16940Sstevel@tonic-gate } 16950Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 16960Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) { 16970Sstevel@tonic-gate *retnconf = nconf; 16980Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs, 16997208Svv149972 listen_backlog)); 17000Sstevel@tonic-gate } 17010Sstevel@tonic-gate } 17020Sstevel@tonic-gate (void) endnetconfig(nc); 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s", 17050Sstevel@tonic-gate proto); 17060Sstevel@tonic-gate return (-1); 17070Sstevel@tonic-gate } 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate #include <netinet/in.h> 17100Sstevel@tonic-gate 17110Sstevel@tonic-gate /* 17120Sstevel@tonic-gate * Create an address mask appropriate for the transport. 17130Sstevel@tonic-gate * The mask is used to obtain the host-specific part of 17140Sstevel@tonic-gate * a network address when comparing addresses. 17150Sstevel@tonic-gate * For an internet address the host-specific part is just 17160Sstevel@tonic-gate * the 32 bit IP address and this part of the mask is set 17170Sstevel@tonic-gate * to all-ones. The port number part of the mask is zeroes. 17180Sstevel@tonic-gate */ 17190Sstevel@tonic-gate static int 17200Sstevel@tonic-gate set_addrmask(fd, nconf, mask) 17210Sstevel@tonic-gate struct netconfig *nconf; 17220Sstevel@tonic-gate struct netbuf *mask; 17230Sstevel@tonic-gate { 17240Sstevel@tonic-gate struct t_info info; 17250Sstevel@tonic-gate 17260Sstevel@tonic-gate /* 17270Sstevel@tonic-gate * Find the size of the address we need to mask. 17280Sstevel@tonic-gate */ 17290Sstevel@tonic-gate if (t_getinfo(fd, &info) < 0) { 17300Sstevel@tonic-gate t_error("t_getinfo"); 17310Sstevel@tonic-gate return (-1); 17320Sstevel@tonic-gate } 17330Sstevel@tonic-gate mask->len = mask->maxlen = info.addr; 17340Sstevel@tonic-gate if (info.addr <= 0) { 17350Sstevel@tonic-gate syslog(LOG_ERR, "set_addrmask: address size: %ld", 17360Sstevel@tonic-gate info.addr); 17370Sstevel@tonic-gate return (-1); 17380Sstevel@tonic-gate } 17390Sstevel@tonic-gate 17400Sstevel@tonic-gate mask->buf = (char *)malloc(mask->len); 17410Sstevel@tonic-gate if (mask->buf == NULL) { 17420Sstevel@tonic-gate syslog(LOG_ERR, "set_addrmask: no memory"); 17430Sstevel@tonic-gate return (-1); 17440Sstevel@tonic-gate } 17450Sstevel@tonic-gate (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */ 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 17480Sstevel@tonic-gate /* 17490Sstevel@tonic-gate * Set the mask so that the port is ignored. 17500Sstevel@tonic-gate */ 17510Sstevel@tonic-gate /* LINTED pointer alignment */ 17520Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr = 17530Sstevel@tonic-gate (ulong_t)~0; 17540Sstevel@tonic-gate /* LINTED pointer alignment */ 17550Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_family = 17560Sstevel@tonic-gate (ushort_t)~0; 17570Sstevel@tonic-gate } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 17580Sstevel@tonic-gate /* LINTED pointer alignment */ 17590Sstevel@tonic-gate (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr, 17600Sstevel@tonic-gate (uchar_t)~0, sizeof (struct in6_addr)); 17610Sstevel@tonic-gate /* LINTED pointer alignment */ 17620Sstevel@tonic-gate ((struct sockaddr_in6 *)mask->buf)->sin6_family = 17630Sstevel@tonic-gate (ushort_t)~0; 17640Sstevel@tonic-gate } else { 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate /* 17670Sstevel@tonic-gate * Set all mask bits. 17680Sstevel@tonic-gate */ 17690Sstevel@tonic-gate (void) memset(mask->buf, 0xFF, mask->len); 17700Sstevel@tonic-gate } 17710Sstevel@tonic-gate return (0); 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate /* 17750Sstevel@tonic-gate * For listen fd's index is always less than end_listen_fds. 17760Sstevel@tonic-gate * end_listen_fds is defined externally in the daemon that uses this library. 17770Sstevel@tonic-gate * It's value is equal to the number of open file descriptors after the 17780Sstevel@tonic-gate * last listen end point was opened but before any connection was accepted. 17790Sstevel@tonic-gate */ 17800Sstevel@tonic-gate static int 17810Sstevel@tonic-gate is_listen_fd_index(int index) 17820Sstevel@tonic-gate { 17830Sstevel@tonic-gate return (index < end_listen_fds); 17840Sstevel@tonic-gate } 1785