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 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * 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 */ 21bbaa8b60SDan Kruchinin 227c478bd9Sstevel@tonic-gate /* 239ff75adeSSurya Prakki * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 24bbaa8b60SDan Kruchinin * Copyright (c) 2012 by Delphix. All rights reserved. 2555393845SMarcel Telka * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 26*09b0d01cSGary Mills * Copyright 2014 Gary Mills 274a030418SDan Kruchinin */ 284a030418SDan Kruchinin 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * nfs_tbind.c, common part for nfsd and lockd. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <tiuser.h> 357c478bd9Sstevel@tonic-gate #include <fcntl.h> 367c478bd9Sstevel@tonic-gate #include <netconfig.h> 377c478bd9Sstevel@tonic-gate #include <stropts.h> 387c478bd9Sstevel@tonic-gate #include <errno.h> 397c478bd9Sstevel@tonic-gate #include <syslog.h> 407c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 417c478bd9Sstevel@tonic-gate #include <sys/time.h> 427c478bd9Sstevel@tonic-gate #include <sys/resource.h> 437c478bd9Sstevel@tonic-gate #include <signal.h> 447c478bd9Sstevel@tonic-gate #include <netdir.h> 457c478bd9Sstevel@tonic-gate #include <unistd.h> 467c478bd9Sstevel@tonic-gate #include <string.h> 477c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 487c478bd9Sstevel@tonic-gate #include <malloc.h> 497c478bd9Sstevel@tonic-gate #include <stdlib.h> 507c478bd9Sstevel@tonic-gate #include "nfs_tbind.h" 517c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 527c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h> 537c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h> 547c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h> 5545916cd2Sjpk #include <zone.h> 5645916cd2Sjpk #include <sys/socket.h> 5745916cd2Sjpk #include <tsol/label.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Determine valid semantics for most applications. 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate #define OK_TPI_TYPE(_nconf) \ 637c478bd9Sstevel@tonic-gate (_nconf->nc_semantics == NC_TPI_CLTS || \ 647c478bd9Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS || \ 657c478bd9Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS_ORD) 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #define BE32_TO_U32(a) \ 687c478bd9Sstevel@tonic-gate ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \ 697c478bd9Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \ 707c478bd9Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \ 717c478bd9Sstevel@tonic-gate ((ulong_t)((uchar_t *)a)[3] & 0xFF)) 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Number of elements to add to the poll array on each allocation. 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate #define POLL_ARRAY_INC_SIZE 64 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Number of file descriptors by which the process soft limit may be 807c478bd9Sstevel@tonic-gate * increased on each call to nofile_increase(0). 817c478bd9Sstevel@tonic-gate */ 827c478bd9Sstevel@tonic-gate #define NOFILE_INC_SIZE 64 837c478bd9Sstevel@tonic-gate 842081ac19SDai Ngo /* 852081ac19SDai Ngo * Default TCP send and receive buffer size of NFS server. 862081ac19SDai Ngo */ 872081ac19SDai Ngo #define NFSD_TCP_BUFSZ (1024*1024) 882081ac19SDai Ngo 897c478bd9Sstevel@tonic-gate struct conn_ind { 907c478bd9Sstevel@tonic-gate struct conn_ind *conn_next; 917c478bd9Sstevel@tonic-gate struct conn_ind *conn_prev; 927c478bd9Sstevel@tonic-gate struct t_call *conn_call; 937c478bd9Sstevel@tonic-gate }; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate struct conn_entry { 967c478bd9Sstevel@tonic-gate bool_t closing; 977c478bd9Sstevel@tonic-gate struct netconfig nc; 987c478bd9Sstevel@tonic-gate }; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * this file contains transport routines common to nfsd and lockd 1027c478bd9Sstevel@tonic-gate */ 1037c478bd9Sstevel@tonic-gate static int nofile_increase(int); 1047c478bd9Sstevel@tonic-gate static int reuseaddr(int); 10545916cd2Sjpk static int recvucred(int); 10645916cd2Sjpk static int anonmlp(int); 1077c478bd9Sstevel@tonic-gate static void add_to_poll_list(int, struct netconfig *); 1087c478bd9Sstevel@tonic-gate static char *serv_name_to_port_name(char *); 1097c478bd9Sstevel@tonic-gate static int bind_to_proto(char *, char *, struct netbuf **, 1107c478bd9Sstevel@tonic-gate struct netconfig **); 1117c478bd9Sstevel@tonic-gate static int bind_to_provider(char *, char *, struct netbuf **, 1127c478bd9Sstevel@tonic-gate struct netconfig **); 1137c478bd9Sstevel@tonic-gate static void conn_close_oldest(void); 1147c478bd9Sstevel@tonic-gate static boolean_t conn_get(int, struct netconfig *, struct conn_ind **); 1157c478bd9Sstevel@tonic-gate static void cots_listen_event(int, int); 1167c478bd9Sstevel@tonic-gate static int discon_get(int, struct netconfig *, struct conn_ind **); 1177c478bd9Sstevel@tonic-gate static int do_poll_clts_action(int, int); 1187c478bd9Sstevel@tonic-gate static int do_poll_cots_action(int, int); 1197c478bd9Sstevel@tonic-gate static void remove_from_poll_list(int); 1207c478bd9Sstevel@tonic-gate static int set_addrmask(int, struct netconfig *, struct netbuf *); 1217c478bd9Sstevel@tonic-gate static int is_listen_fd_index(int); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static struct pollfd *poll_array; 1247c478bd9Sstevel@tonic-gate static struct conn_entry *conn_polled; 1257c478bd9Sstevel@tonic-gate static int num_conns; /* Current number of connections */ 1267c478bd9Sstevel@tonic-gate int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int, 1277c478bd9Sstevel@tonic-gate struct netbuf *); 1282081ac19SDai Ngo static int setopt(int fd, int level, int name, int value); 1292081ac19SDai Ngo static int get_opt(int fd, int level, int name); 1302081ac19SDai Ngo static void nfslib_set_sockbuf(int fd); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate /* 1337c478bd9Sstevel@tonic-gate * Called to create and prepare a transport descriptor for in-kernel 1347c478bd9Sstevel@tonic-gate * RPC service. 1357c478bd9Sstevel@tonic-gate * Returns -1 on failure and a valid descriptor on success. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate int 1387c478bd9Sstevel@tonic-gate nfslib_transport_open(struct netconfig *nconf) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate int fd; 1417c478bd9Sstevel@tonic-gate struct strioctl strioc; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate if ((nconf == (struct netconfig *)NULL) || 1447c478bd9Sstevel@tonic-gate (nconf->nc_device == (char *)NULL)) { 1457c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "no netconfig device"); 1467c478bd9Sstevel@tonic-gate return (-1); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * Open the transport device. 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL); 1537c478bd9Sstevel@tonic-gate if (fd == -1) { 1547c478bd9Sstevel@tonic-gate if (t_errno == TSYSERR && errno == EMFILE && 1557c478bd9Sstevel@tonic-gate (nofile_increase(0) == 0)) { 1567c478bd9Sstevel@tonic-gate /* Try again with a higher NOFILE limit. */ 1577c478bd9Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, 1587c478bd9Sstevel@tonic-gate (struct t_info *)NULL); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate if (fd == -1) { 1617c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m", 1627c478bd9Sstevel@tonic-gate nconf->nc_device, t_errno); 1637c478bd9Sstevel@tonic-gate return (-1); 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Pop timod because the RPC module must be as close as possible 1697c478bd9Sstevel@tonic-gate * to the transport. 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate if (ioctl(fd, I_POP, 0) < 0) { 1727c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "I_POP of timod failed: %m"); 1737c478bd9Sstevel@tonic-gate (void) t_close(fd); 1747c478bd9Sstevel@tonic-gate return (-1); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * Common code for CLTS and COTS transports 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "rpcmod") < 0) { 1817c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m"); 1827c478bd9Sstevel@tonic-gate (void) t_close(fd); 1837c478bd9Sstevel@tonic-gate return (-1); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate strioc.ic_cmd = RPC_SERVER; 1877c478bd9Sstevel@tonic-gate strioc.ic_dp = (char *)0; 1887c478bd9Sstevel@tonic-gate strioc.ic_len = 0; 1897c478bd9Sstevel@tonic-gate strioc.ic_timout = -1; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* Tell rpcmod to act like a server stream. */ 1927c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &strioc) < 0) { 1937c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m"); 1947c478bd9Sstevel@tonic-gate (void) t_close(fd); 1957c478bd9Sstevel@tonic-gate return (-1); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Re-push timod so that we will still be doing TLI 2007c478bd9Sstevel@tonic-gate * operations on the descriptor. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "timod") < 0) { 2037c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of timod failed: %m"); 2047c478bd9Sstevel@tonic-gate (void) t_close(fd); 2057c478bd9Sstevel@tonic-gate return (-1); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 208e810a982Svv149972 /* 209e810a982Svv149972 * Enable options of returning the ip's for udp. 210e810a982Svv149972 */ 211e810a982Svv149972 if (strcmp(nconf->nc_netid, "udp6") == 0) 212e810a982Svv149972 __rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1); 213e810a982Svv149972 else if (strcmp(nconf->nc_netid, "udp") == 0) 214e810a982Svv149972 __rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1); 215e810a982Svv149972 2167c478bd9Sstevel@tonic-gate return (fd); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate static int 2207c478bd9Sstevel@tonic-gate nofile_increase(int limit) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate struct rlimit rl; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { 2257c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getrlimit of NOFILE failed: %m"); 2267c478bd9Sstevel@tonic-gate return (-1); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate if (limit > 0) 2307c478bd9Sstevel@tonic-gate rl.rlim_cur = limit; 2317c478bd9Sstevel@tonic-gate else 2327c478bd9Sstevel@tonic-gate rl.rlim_cur += NOFILE_INC_SIZE; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (rl.rlim_cur > rl.rlim_max && 2357c478bd9Sstevel@tonic-gate rl.rlim_max != RLIM_INFINITY) 2367c478bd9Sstevel@tonic-gate rl.rlim_max = rl.rlim_cur; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 2397c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m", 2407c478bd9Sstevel@tonic-gate rl.rlim_cur); 2417c478bd9Sstevel@tonic-gate return (-1); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate return (0); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2472081ac19SDai Ngo static void 2482081ac19SDai Ngo nfslib_set_sockbuf(int fd) 2492081ac19SDai Ngo { 2502081ac19SDai Ngo int curval, val; 2512081ac19SDai Ngo 2522081ac19SDai Ngo val = NFSD_TCP_BUFSZ; 2532081ac19SDai Ngo 2542081ac19SDai Ngo curval = get_opt(fd, SOL_SOCKET, SO_SNDBUF); 2552081ac19SDai Ngo syslog(LOG_DEBUG, "Current SO_SNDBUF value is %d", curval); 2562081ac19SDai Ngo if ((curval != -1) && (curval < val)) { 2572081ac19SDai Ngo syslog(LOG_DEBUG, "Set SO_SNDBUF option to %d", val); 2582081ac19SDai Ngo if (setopt(fd, SOL_SOCKET, SO_SNDBUF, val) < 0) { 2592081ac19SDai Ngo syslog(LOG_ERR, 2602081ac19SDai Ngo "couldn't set SO_SNDBUF to %d - t_errno = %d", 2612081ac19SDai Ngo val, t_errno); 2622081ac19SDai Ngo syslog(LOG_ERR, 2632081ac19SDai Ngo "Check and increase system-wide tcp_max_buf"); 2642081ac19SDai Ngo } 2652081ac19SDai Ngo } 2662081ac19SDai Ngo 2672081ac19SDai Ngo curval = get_opt(fd, SOL_SOCKET, SO_RCVBUF); 2682081ac19SDai Ngo syslog(LOG_DEBUG, "Current SO_RCVBUF value is %d", curval); 2692081ac19SDai Ngo if ((curval != -1) && (curval < val)) { 2702081ac19SDai Ngo syslog(LOG_DEBUG, "Set SO_RCVBUF option to %d", val); 2712081ac19SDai Ngo if (setopt(fd, SOL_SOCKET, SO_RCVBUF, val) < 0) { 2722081ac19SDai Ngo syslog(LOG_ERR, 2732081ac19SDai Ngo "couldn't set SO_RCVBUF to %d - t_errno = %d", 2742081ac19SDai Ngo val, t_errno); 2752081ac19SDai Ngo syslog(LOG_ERR, 2762081ac19SDai Ngo "Check and increase system-wide tcp_max_buf"); 2772081ac19SDai Ngo } 2782081ac19SDai Ngo } 2792081ac19SDai Ngo } 2802081ac19SDai Ngo 2817c478bd9Sstevel@tonic-gate int 2827c478bd9Sstevel@tonic-gate nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, 2837c478bd9Sstevel@tonic-gate struct nd_hostserv *hs, int backlog) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate int fd; 2867c478bd9Sstevel@tonic-gate struct t_bind *ntb; 2877c478bd9Sstevel@tonic-gate struct t_bind tb; 2887c478bd9Sstevel@tonic-gate struct nd_addrlist *addrlist; 2897c478bd9Sstevel@tonic-gate struct t_optmgmt req, resp; 2907c478bd9Sstevel@tonic-gate struct opthdr *opt; 2917c478bd9Sstevel@tonic-gate char reqbuf[128]; 2927c478bd9Sstevel@tonic-gate bool_t use_any = FALSE; 29345916cd2Sjpk bool_t gzone = TRUE; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if ((fd = nfslib_transport_open(nconf)) == -1) { 2967c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "cannot establish transport service over %s", 2977c478bd9Sstevel@tonic-gate nconf->nc_device); 2987c478bd9Sstevel@tonic-gate return (-1); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate addrlist = (struct nd_addrlist *)NULL; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* nfs4_callback service does not used a fieed port number */ 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate if (strcmp(hs->h_serv, "nfs4_callback") == 0) { 3067c478bd9Sstevel@tonic-gate tb.addr.maxlen = 0; 3077c478bd9Sstevel@tonic-gate tb.addr.len = 0; 3087c478bd9Sstevel@tonic-gate tb.addr.buf = 0; 3097c478bd9Sstevel@tonic-gate use_any = TRUE; 31045916cd2Sjpk gzone = (getzoneid() == GLOBAL_ZONEID); 3117c478bd9Sstevel@tonic-gate } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) { 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 3147c478bd9Sstevel@tonic-gate "Cannot get address for transport %s host %s service %s", 3157c478bd9Sstevel@tonic-gate nconf->nc_netid, hs->h_host, hs->h_serv); 3167c478bd9Sstevel@tonic-gate (void) t_close(fd); 3177c478bd9Sstevel@tonic-gate return (-1); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) { 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * If we're running over TCP, then set the 3237c478bd9Sstevel@tonic-gate * SO_REUSEADDR option so that we can bind 3247c478bd9Sstevel@tonic-gate * to our preferred address even if previously 3257c478bd9Sstevel@tonic-gate * left connections exist in FIN_WAIT states. 3267c478bd9Sstevel@tonic-gate * This is somewhat bogus, but otherwise you have 3277c478bd9Sstevel@tonic-gate * to wait 2 minutes to restart after killing it. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate if (reuseaddr(fd) == -1) { 3307c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 3317c478bd9Sstevel@tonic-gate "couldn't set SO_REUSEADDR option on transport"); 3327c478bd9Sstevel@tonic-gate } 33345916cd2Sjpk } else if (strcmp(nconf->nc_proto, "udp") == 0) { 33445916cd2Sjpk /* 33545916cd2Sjpk * In order to run MLP on UDP, we need to handle creds. 33645916cd2Sjpk */ 33745916cd2Sjpk if (recvucred(fd) == -1) { 33845916cd2Sjpk syslog(LOG_WARNING, 33945916cd2Sjpk "couldn't set SO_RECVUCRED option on transport"); 34045916cd2Sjpk } 34145916cd2Sjpk } 34245916cd2Sjpk 34345916cd2Sjpk /* 34445916cd2Sjpk * Make non global zone nfs4_callback port MLP 34545916cd2Sjpk */ 34645916cd2Sjpk if (use_any && is_system_labeled() && !gzone) { 34745916cd2Sjpk if (anonmlp(fd) == -1) { 34845916cd2Sjpk /* 34945916cd2Sjpk * failing to set this option means nfs4_callback 35045916cd2Sjpk * could fail silently later. So fail it with 35145916cd2Sjpk * with an error message now. 35245916cd2Sjpk */ 35345916cd2Sjpk syslog(LOG_ERR, 35445916cd2Sjpk "couldn't set SO_ANON_MLP option on transport"); 35545916cd2Sjpk (void) t_close(fd); 35645916cd2Sjpk return (-1); 35745916cd2Sjpk } 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_CLTS) 3617c478bd9Sstevel@tonic-gate tb.qlen = 0; 3627c478bd9Sstevel@tonic-gate else 3637c478bd9Sstevel@tonic-gate tb.qlen = backlog; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 3667c478bd9Sstevel@tonic-gate ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL); 3677c478bd9Sstevel@tonic-gate if (ntb == (struct t_bind *)NULL) { 3687c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno); 3697c478bd9Sstevel@tonic-gate (void) t_close(fd); 3707c478bd9Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 3717c478bd9Sstevel@tonic-gate return (-1); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * XXX - what about the space tb->addr.buf points to? This should 3767c478bd9Sstevel@tonic-gate * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,) 3777c478bd9Sstevel@tonic-gate * should't be called with T_ALL. 3787c478bd9Sstevel@tonic-gate */ 3797c478bd9Sstevel@tonic-gate if (addrlist) 3807c478bd9Sstevel@tonic-gate tb.addr = *(addrlist->n_addrs); /* structure copy */ 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate if (t_bind(fd, &tb, ntb) == -1) { 3837c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno); 3847c478bd9Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND); 3857c478bd9Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 3867c478bd9Sstevel@tonic-gate (void) t_close(fd); 3877c478bd9Sstevel@tonic-gate return (-1); 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* make sure we bound to the right address */ 3917c478bd9Sstevel@tonic-gate if (use_any == FALSE && 3927c478bd9Sstevel@tonic-gate (tb.addr.len != ntb->addr.len || 3937c478bd9Sstevel@tonic-gate memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) { 3947c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "t_bind to wrong address"); 3957c478bd9Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND); 3967c478bd9Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 3977c478bd9Sstevel@tonic-gate (void) t_close(fd); 3987c478bd9Sstevel@tonic-gate return (-1); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * Call nfs4svc_setport so that the kernel can be 4037c478bd9Sstevel@tonic-gate * informed what port number the daemon is listing 4047c478bd9Sstevel@tonic-gate * for incoming connection requests. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS || 4087c478bd9Sstevel@tonic-gate nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL) 4097c478bd9Sstevel@tonic-gate (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate *addr = &ntb->addr; 4127c478bd9Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) { 4157c478bd9Sstevel@tonic-gate /* 4167c478bd9Sstevel@tonic-gate * Disable the Nagle algorithm on TCP connections. 4177c478bd9Sstevel@tonic-gate * Connections accepted from this listener will 4187c478bd9Sstevel@tonic-gate * inherit the listener options. 4197c478bd9Sstevel@tonic-gate */ 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 4227c478bd9Sstevel@tonic-gate opt = (struct opthdr *)reqbuf; 4237c478bd9Sstevel@tonic-gate opt->level = IPPROTO_TCP; 4247c478bd9Sstevel@tonic-gate opt->name = TCP_NODELAY; 4257c478bd9Sstevel@tonic-gate opt->len = sizeof (int); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 4287c478bd9Sstevel@tonic-gate *(int *)((char *)opt + sizeof (*opt)) = 1; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate req.flags = T_NEGOTIATE; 4317c478bd9Sstevel@tonic-gate req.opt.len = sizeof (*opt) + opt->len; 4327c478bd9Sstevel@tonic-gate req.opt.buf = (char *)opt; 4337c478bd9Sstevel@tonic-gate resp.flags = 0; 4347c478bd9Sstevel@tonic-gate resp.opt.buf = reqbuf; 4357c478bd9Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || 4387c478bd9Sstevel@tonic-gate resp.flags != T_SUCCESS) { 4397c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 4407c478bd9Sstevel@tonic-gate "couldn't set NODELAY option for proto %s: t_errno = %d, %m", 4417c478bd9Sstevel@tonic-gate nconf->nc_proto, t_errno); 4427c478bd9Sstevel@tonic-gate } 4432081ac19SDai Ngo 4442081ac19SDai Ngo nfslib_set_sockbuf(fd); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate return (fd); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate static int 4512081ac19SDai Ngo get_opt(int fd, int level, int name) 4522081ac19SDai Ngo { 4532081ac19SDai Ngo struct t_optmgmt req, res; 4542081ac19SDai Ngo struct { 4552081ac19SDai Ngo struct opthdr opt; 4562081ac19SDai Ngo int value; 4572081ac19SDai Ngo } reqbuf; 4582081ac19SDai Ngo 4592081ac19SDai Ngo reqbuf.opt.level = level; 4602081ac19SDai Ngo reqbuf.opt.name = name; 4612081ac19SDai Ngo reqbuf.opt.len = sizeof (int); 4622081ac19SDai Ngo reqbuf.value = 0; 4632081ac19SDai Ngo 4642081ac19SDai Ngo req.flags = T_CURRENT; 4652081ac19SDai Ngo req.opt.len = sizeof (reqbuf); 4662081ac19SDai Ngo req.opt.buf = (char *)&reqbuf; 4672081ac19SDai Ngo 4682081ac19SDai Ngo res.flags = 0; 4692081ac19SDai Ngo res.opt.buf = (char *)&reqbuf; 4702081ac19SDai Ngo res.opt.maxlen = sizeof (reqbuf); 4712081ac19SDai Ngo 4722081ac19SDai Ngo if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) { 4732081ac19SDai Ngo t_error("t_optmgmt"); 4742081ac19SDai Ngo return (-1); 4752081ac19SDai Ngo } 4762081ac19SDai Ngo return (reqbuf.value); 4772081ac19SDai Ngo } 4782081ac19SDai Ngo 4792081ac19SDai Ngo static int 48045916cd2Sjpk setopt(int fd, int level, int name, int value) 4817c478bd9Sstevel@tonic-gate { 4827c478bd9Sstevel@tonic-gate struct t_optmgmt req, resp; 48345916cd2Sjpk struct { 48445916cd2Sjpk struct opthdr opt; 48545916cd2Sjpk int value; 48645916cd2Sjpk } reqbuf; 4877c478bd9Sstevel@tonic-gate 48845916cd2Sjpk reqbuf.opt.level = level; 48945916cd2Sjpk reqbuf.opt.name = name; 49045916cd2Sjpk reqbuf.opt.len = sizeof (int); 4917c478bd9Sstevel@tonic-gate 49245916cd2Sjpk reqbuf.value = value; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate req.flags = T_NEGOTIATE; 49545916cd2Sjpk req.opt.len = sizeof (reqbuf); 49645916cd2Sjpk req.opt.buf = (char *)&reqbuf; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate resp.flags = 0; 49945916cd2Sjpk resp.opt.buf = (char *)&reqbuf; 5007c478bd9Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 5037c478bd9Sstevel@tonic-gate t_error("t_optmgmt"); 5047c478bd9Sstevel@tonic-gate return (-1); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate return (0); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 50945916cd2Sjpk static int 51045916cd2Sjpk reuseaddr(int fd) 51145916cd2Sjpk { 51245916cd2Sjpk return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1)); 51345916cd2Sjpk } 51445916cd2Sjpk 51545916cd2Sjpk static int 51645916cd2Sjpk recvucred(int fd) 51745916cd2Sjpk { 51845916cd2Sjpk return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1)); 51945916cd2Sjpk } 52045916cd2Sjpk 52145916cd2Sjpk static int 52245916cd2Sjpk anonmlp(int fd) 52345916cd2Sjpk { 52445916cd2Sjpk return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1)); 52545916cd2Sjpk } 52645916cd2Sjpk 5277c478bd9Sstevel@tonic-gate void 5287c478bd9Sstevel@tonic-gate nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf) 5297c478bd9Sstevel@tonic-gate { 5307c478bd9Sstevel@tonic-gate int error; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * Save the error code across syslog(), just in case syslog() 5347c478bd9Sstevel@tonic-gate * gets its own error and, therefore, overwrites errno. 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate error = errno; 5377c478bd9Sstevel@tonic-gate if (t_errno == TSYSERR) { 5387c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m", 5397c478bd9Sstevel@tonic-gate tli_name, fd, nconf->nc_proto); 5407c478bd9Sstevel@tonic-gate } else { 5417c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 5427c478bd9Sstevel@tonic-gate "%s(file descriptor %d/transport %s) TLI error %d", 5437c478bd9Sstevel@tonic-gate tli_name, fd, nconf->nc_proto, t_errno); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate errno = error; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate /* 5497c478bd9Sstevel@tonic-gate * Called to set up service over a particular transport. 5507c478bd9Sstevel@tonic-gate */ 5517c478bd9Sstevel@tonic-gate void 5527c478bd9Sstevel@tonic-gate do_one(char *provider, NETSELDECL(proto), struct protob *protobp0, 5539ff75adeSSurya Prakki int (*svc)(int, struct netbuf, struct netconfig *)) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate register int sock; 5567c478bd9Sstevel@tonic-gate struct protob *protobp; 5577c478bd9Sstevel@tonic-gate struct netbuf *retaddr; 5587c478bd9Sstevel@tonic-gate struct netconfig *retnconf; 5597c478bd9Sstevel@tonic-gate struct netbuf addrmask; 5607c478bd9Sstevel@tonic-gate int vers; 5617c478bd9Sstevel@tonic-gate int err; 5627c478bd9Sstevel@tonic-gate int l; 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate if (provider) 5657c478bd9Sstevel@tonic-gate sock = bind_to_provider(provider, protobp0->serv, &retaddr, 5667c478bd9Sstevel@tonic-gate &retnconf); 5677c478bd9Sstevel@tonic-gate else 5687c478bd9Sstevel@tonic-gate sock = bind_to_proto(proto, protobp0->serv, &retaddr, 5697c478bd9Sstevel@tonic-gate &retnconf); 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate if (sock == -1) { 5727c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 5737c478bd9Sstevel@tonic-gate "Cannot establish %s service over %s: transport setup problem.", 5747c478bd9Sstevel@tonic-gate protobp0->serv, provider ? provider : proto); 5757c478bd9Sstevel@tonic-gate return; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate if (set_addrmask(sock, retnconf, &addrmask) < 0) { 5797c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 5807c478bd9Sstevel@tonic-gate "Cannot set address mask for %s", retnconf->nc_netid); 5817c478bd9Sstevel@tonic-gate return; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * Register all versions of the programs in the protocol block list. 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate l = strlen(NC_UDP); 5887c478bd9Sstevel@tonic-gate for (protobp = protobp0; protobp; protobp = protobp->next) { 5897c478bd9Sstevel@tonic-gate for (vers = protobp->versmin; vers <= protobp->versmax; 5907c478bd9Sstevel@tonic-gate vers++) { 5917c478bd9Sstevel@tonic-gate if ((protobp->program == NFS_PROGRAM || 5927c478bd9Sstevel@tonic-gate protobp->program == NFS_ACL_PROGRAM) && 5937c478bd9Sstevel@tonic-gate vers == NFS_V4 && 5947c478bd9Sstevel@tonic-gate strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0) 5957c478bd9Sstevel@tonic-gate continue; 5967c478bd9Sstevel@tonic-gate 5979ff75adeSSurya Prakki (void) rpcb_unset(protobp->program, vers, retnconf); 5989ff75adeSSurya Prakki (void) rpcb_set(protobp->program, vers, retnconf, 5999ff75adeSSurya Prakki retaddr); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6034a030418SDan Kruchinin /* 6044a030418SDan Kruchinin * Register services with CLTS semantics right now. 6054a030418SDan Kruchinin * Note: services with COTS/COTS_ORD semantics will be 6064a030418SDan Kruchinin * registered later from cots_listen_event function. 6074a030418SDan Kruchinin */ 6087c478bd9Sstevel@tonic-gate if (retnconf->nc_semantics == NC_TPI_CLTS) { 6097c478bd9Sstevel@tonic-gate /* Don't drop core if supporting module(s) aren't loaded. */ 6107c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, SIG_IGN); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6137c478bd9Sstevel@tonic-gate * svc() doesn't block, it returns success or failure. 6147c478bd9Sstevel@tonic-gate */ 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if (svc == NULL && Mysvc4 != NULL) 6177c478bd9Sstevel@tonic-gate err = (*Mysvc4)(sock, &addrmask, retnconf, 6187c478bd9Sstevel@tonic-gate NFS4_SETPORT|NFS4_KRPC_START, retaddr); 6197c478bd9Sstevel@tonic-gate else 6207c478bd9Sstevel@tonic-gate err = (*svc)(sock, addrmask, retnconf); 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate if (err < 0) { 6237c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 6247c478bd9Sstevel@tonic-gate "Cannot establish %s service over <file desc." 6257c478bd9Sstevel@tonic-gate " %d, protocol %s> : %m. Exiting", 6267c478bd9Sstevel@tonic-gate protobp0->serv, sock, retnconf->nc_proto); 6277c478bd9Sstevel@tonic-gate exit(1); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate } 6304a030418SDan Kruchinin free(addrmask.buf); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * We successfully set up the server over this transport. 6347c478bd9Sstevel@tonic-gate * Add this descriptor to the one being polled on. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate add_to_poll_list(sock, retnconf); 6377c478bd9Sstevel@tonic-gate } 6382081ac19SDai Ngo 6397c478bd9Sstevel@tonic-gate /* 6407c478bd9Sstevel@tonic-gate * Set up the NFS service over all the available transports. 6417c478bd9Sstevel@tonic-gate * Returns -1 for failure, 0 for success. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate int 6447c478bd9Sstevel@tonic-gate do_all(struct protob *protobp, 6459ff75adeSSurya Prakki int (*svc)(int, struct netbuf, struct netconfig *)) 6467c478bd9Sstevel@tonic-gate { 6477c478bd9Sstevel@tonic-gate struct netconfig *nconf; 6487c478bd9Sstevel@tonic-gate NCONF_HANDLE *nc; 6497c478bd9Sstevel@tonic-gate int l; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 6527c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 6537c478bd9Sstevel@tonic-gate return (-1); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate l = strlen(NC_UDP); 6567c478bd9Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 6577c478bd9Sstevel@tonic-gate if ((nconf->nc_flag & NC_VISIBLE) && 6587c478bd9Sstevel@tonic-gate strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 && 6597c478bd9Sstevel@tonic-gate OK_TPI_TYPE(nconf) && 6607c478bd9Sstevel@tonic-gate (protobp->program != NFS4_CALLBACK || 6617c478bd9Sstevel@tonic-gate strncasecmp(nconf->nc_proto, NC_UDP, l) != 0)) 6627c478bd9Sstevel@tonic-gate do_one(nconf->nc_device, nconf->nc_proto, 6639ff75adeSSurya Prakki protobp, svc); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate (void) endnetconfig(nc); 6667c478bd9Sstevel@tonic-gate return (0); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * poll on the open transport descriptors for events and errors. 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate void 6737c478bd9Sstevel@tonic-gate poll_for_action(void) 6747c478bd9Sstevel@tonic-gate { 6757c478bd9Sstevel@tonic-gate int nfds; 6767c478bd9Sstevel@tonic-gate int i; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * Keep polling until all transports have been closed. When this 6807c478bd9Sstevel@tonic-gate * happens, we return. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate while ((int)num_fds > 0) { 6837c478bd9Sstevel@tonic-gate nfds = poll(poll_array, num_fds, INFTIM); 6847c478bd9Sstevel@tonic-gate switch (nfds) { 6857c478bd9Sstevel@tonic-gate case 0: 6867c478bd9Sstevel@tonic-gate continue; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate case -1: 6897c478bd9Sstevel@tonic-gate /* 6907c478bd9Sstevel@tonic-gate * Some errors from poll could be 6917c478bd9Sstevel@tonic-gate * due to temporary conditions, and we try to 6927c478bd9Sstevel@tonic-gate * be robust in the face of them. Other 6937c478bd9Sstevel@tonic-gate * errors (should never happen in theory) 6947c478bd9Sstevel@tonic-gate * are fatal (eg. EINVAL, EFAULT). 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate switch (errno) { 6977c478bd9Sstevel@tonic-gate case EINTR: 6987c478bd9Sstevel@tonic-gate continue; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate case EAGAIN: 7017c478bd9Sstevel@tonic-gate case ENOMEM: 7027c478bd9Sstevel@tonic-gate (void) sleep(10); 7037c478bd9Sstevel@tonic-gate continue; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate default: 7067c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 7077c478bd9Sstevel@tonic-gate "poll failed: %m. Exiting"); 7087c478bd9Sstevel@tonic-gate exit(1); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate default: 7117c478bd9Sstevel@tonic-gate break; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * Go through the poll list looking for events. 7167c478bd9Sstevel@tonic-gate */ 7177c478bd9Sstevel@tonic-gate for (i = 0; i < num_fds && nfds > 0; i++) { 7187c478bd9Sstevel@tonic-gate if (poll_array[i].revents) { 7197c478bd9Sstevel@tonic-gate nfds--; 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * We have a message, so try to read it. 7227c478bd9Sstevel@tonic-gate * Record the error return in errno, 7237c478bd9Sstevel@tonic-gate * so that syslog(LOG_ERR, "...%m") 7247c478bd9Sstevel@tonic-gate * dumps the corresponding error string. 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate if (conn_polled[i].nc.nc_semantics == 7277c478bd9Sstevel@tonic-gate NC_TPI_CLTS) { 7287c478bd9Sstevel@tonic-gate errno = do_poll_clts_action( 7297c478bd9Sstevel@tonic-gate poll_array[i].fd, i); 7307c478bd9Sstevel@tonic-gate } else { 7317c478bd9Sstevel@tonic-gate errno = do_poll_cots_action( 7327c478bd9Sstevel@tonic-gate poll_array[i].fd, i); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if (errno == 0) 7367c478bd9Sstevel@tonic-gate continue; 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * Most returned error codes mean that there is 7397c478bd9Sstevel@tonic-gate * fatal condition which we can only deal with 7407c478bd9Sstevel@tonic-gate * by closing the transport. 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate if (errno != EAGAIN && errno != ENOMEM) { 7437c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 7447c478bd9Sstevel@tonic-gate "Error (%m) reading descriptor %d/transport %s. Closing it.", 7457c478bd9Sstevel@tonic-gate poll_array[i].fd, 7467c478bd9Sstevel@tonic-gate conn_polled[i].nc.nc_proto); 7477c478bd9Sstevel@tonic-gate (void) t_close(poll_array[i].fd); 7487c478bd9Sstevel@tonic-gate remove_from_poll_list(poll_array[i].fd); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate } else if (errno == ENOMEM) 7517c478bd9Sstevel@tonic-gate (void) sleep(5); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 7577c478bd9Sstevel@tonic-gate "All transports have been closed with errors. Exiting."); 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* 7617c478bd9Sstevel@tonic-gate * Allocate poll/transport array entries for this descriptor. 7627c478bd9Sstevel@tonic-gate */ 7637c478bd9Sstevel@tonic-gate static void 7647c478bd9Sstevel@tonic-gate add_to_poll_list(int fd, struct netconfig *nconf) 7657c478bd9Sstevel@tonic-gate { 7667c478bd9Sstevel@tonic-gate static int poll_array_size = 0; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate /* 7697c478bd9Sstevel@tonic-gate * If the arrays are full, allocate new ones. 7707c478bd9Sstevel@tonic-gate */ 7717c478bd9Sstevel@tonic-gate if (num_fds == poll_array_size) { 7727c478bd9Sstevel@tonic-gate struct pollfd *tpa; 7737c478bd9Sstevel@tonic-gate struct conn_entry *tnp; 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate if (poll_array_size != 0) { 7767c478bd9Sstevel@tonic-gate tpa = poll_array; 7777c478bd9Sstevel@tonic-gate tnp = conn_polled; 7787c478bd9Sstevel@tonic-gate } else 7797c478bd9Sstevel@tonic-gate tpa = (struct pollfd *)0; 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate poll_array_size += POLL_ARRAY_INC_SIZE; 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * Allocate new arrays. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate poll_array = (struct pollfd *) 7867c478bd9Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct pollfd) + 256); 7877c478bd9Sstevel@tonic-gate conn_polled = (struct conn_entry *) 7887c478bd9Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct conn_entry) + 256); 7897c478bd9Sstevel@tonic-gate if (poll_array == (struct pollfd *)NULL || 7907c478bd9Sstevel@tonic-gate conn_polled == (struct conn_entry *)NULL) { 7917c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "malloc failed for poll array"); 7927c478bd9Sstevel@tonic-gate exit(1); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* 7967c478bd9Sstevel@tonic-gate * Copy the data of the old ones into new arrays, and 7977c478bd9Sstevel@tonic-gate * free the old ones. 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate if (tpa) { 8007c478bd9Sstevel@tonic-gate (void) memcpy((void *)poll_array, (void *)tpa, 8017c478bd9Sstevel@tonic-gate num_fds * sizeof (struct pollfd)); 8027c478bd9Sstevel@tonic-gate (void) memcpy((void *)conn_polled, (void *)tnp, 8037c478bd9Sstevel@tonic-gate num_fds * sizeof (struct conn_entry)); 8047c478bd9Sstevel@tonic-gate free((void *)tpa); 8057c478bd9Sstevel@tonic-gate free((void *)tnp); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 8107c478bd9Sstevel@tonic-gate * Set the descriptor and event list. All possible events are 8117c478bd9Sstevel@tonic-gate * polled for. 8127c478bd9Sstevel@tonic-gate */ 8137c478bd9Sstevel@tonic-gate poll_array[num_fds].fd = fd; 8147c478bd9Sstevel@tonic-gate poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate /* 8177c478bd9Sstevel@tonic-gate * Copy the transport data over too. 8187c478bd9Sstevel@tonic-gate */ 8197c478bd9Sstevel@tonic-gate conn_polled[num_fds].nc = *nconf; 8207c478bd9Sstevel@tonic-gate conn_polled[num_fds].closing = 0; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * Set the descriptor to non-blocking. Avoids a race 8247c478bd9Sstevel@tonic-gate * between data arriving on the stream and then having it 8257c478bd9Sstevel@tonic-gate * flushed before we can read it. 8267c478bd9Sstevel@tonic-gate */ 8277c478bd9Sstevel@tonic-gate if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 8287c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 8297c478bd9Sstevel@tonic-gate "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting", 8307c478bd9Sstevel@tonic-gate num_fds, nconf->nc_proto); 8317c478bd9Sstevel@tonic-gate exit(1); 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate /* 8357c478bd9Sstevel@tonic-gate * Count this descriptor. 8367c478bd9Sstevel@tonic-gate */ 8377c478bd9Sstevel@tonic-gate ++num_fds; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate static void 8417c478bd9Sstevel@tonic-gate remove_from_poll_list(int fd) 8427c478bd9Sstevel@tonic-gate { 8437c478bd9Sstevel@tonic-gate int i; 8447c478bd9Sstevel@tonic-gate int num_to_copy; 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate for (i = 0; i < num_fds; i++) { 8477c478bd9Sstevel@tonic-gate if (poll_array[i].fd == fd) { 8487c478bd9Sstevel@tonic-gate --num_fds; 8497c478bd9Sstevel@tonic-gate num_to_copy = num_fds - i; 8507c478bd9Sstevel@tonic-gate (void) memcpy((void *)&poll_array[i], 8517c478bd9Sstevel@tonic-gate (void *)&poll_array[i+1], 8527c478bd9Sstevel@tonic-gate num_to_copy * sizeof (struct pollfd)); 8537c478bd9Sstevel@tonic-gate (void) memset((void *)&poll_array[num_fds], 0, 8547c478bd9Sstevel@tonic-gate sizeof (struct pollfd)); 8557c478bd9Sstevel@tonic-gate (void) memcpy((void *)&conn_polled[i], 8567c478bd9Sstevel@tonic-gate (void *)&conn_polled[i+1], 8577c478bd9Sstevel@tonic-gate num_to_copy * sizeof (struct conn_entry)); 8587c478bd9Sstevel@tonic-gate (void) memset((void *)&conn_polled[num_fds], 0, 8597c478bd9Sstevel@tonic-gate sizeof (struct conn_entry)); 8607c478bd9Sstevel@tonic-gate return; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list"); 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * Called to read and interpret the event on a connectionless descriptor. 8697c478bd9Sstevel@tonic-gate * Returns 0 if successful, or a UNIX error code if failure. 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate static int 8727c478bd9Sstevel@tonic-gate do_poll_clts_action(int fd, int conn_index) 8737c478bd9Sstevel@tonic-gate { 8747c478bd9Sstevel@tonic-gate int error; 8757c478bd9Sstevel@tonic-gate int ret; 8767c478bd9Sstevel@tonic-gate int flags; 8777c478bd9Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc; 8787c478bd9Sstevel@tonic-gate static struct t_unitdata *unitdata = NULL; 8797c478bd9Sstevel@tonic-gate static struct t_uderr *uderr = NULL; 8807c478bd9Sstevel@tonic-gate static int oldfd = -1; 8817c478bd9Sstevel@tonic-gate struct nd_hostservlist *host = NULL; 8827c478bd9Sstevel@tonic-gate struct strbuf ctl[1], data[1]; 8837c478bd9Sstevel@tonic-gate /* 8847c478bd9Sstevel@tonic-gate * We just need to have some space to consume the 8857c478bd9Sstevel@tonic-gate * message in the event we can't use the TLI interface to do the 8867c478bd9Sstevel@tonic-gate * job. 8877c478bd9Sstevel@tonic-gate * 8887c478bd9Sstevel@tonic-gate * We flush the message using getmsg(). For the control part 8897c478bd9Sstevel@tonic-gate * we allocate enough for any TPI header plus 32 bytes for address 8907c478bd9Sstevel@tonic-gate * and options. For the data part, there is nothing magic about 8917c478bd9Sstevel@tonic-gate * the size of the array, but 256 bytes is probably better than 8927c478bd9Sstevel@tonic-gate * 1 byte, and we don't expect any data portion anyway. 8937c478bd9Sstevel@tonic-gate * 8947c478bd9Sstevel@tonic-gate * If the array sizes are too small, we handle this because getmsg() 8957c478bd9Sstevel@tonic-gate * (called to consume the message) will return MOREDATA|MORECTL. 8967c478bd9Sstevel@tonic-gate * Thus we just call getmsg() until it's read the message. 8977c478bd9Sstevel@tonic-gate */ 8987c478bd9Sstevel@tonic-gate char ctlbuf[sizeof (union T_primitives) + 32]; 8997c478bd9Sstevel@tonic-gate char databuf[256]; 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate /* 9027c478bd9Sstevel@tonic-gate * If this is the same descriptor as the last time 9037c478bd9Sstevel@tonic-gate * do_poll_clts_action was called, we can save some 9047c478bd9Sstevel@tonic-gate * de-allocation and allocation. 9057c478bd9Sstevel@tonic-gate */ 9067c478bd9Sstevel@tonic-gate if (oldfd != fd) { 9077c478bd9Sstevel@tonic-gate oldfd = fd; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate if (unitdata) { 9107c478bd9Sstevel@tonic-gate (void) t_free((char *)unitdata, T_UNITDATA); 9117c478bd9Sstevel@tonic-gate unitdata = NULL; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate if (uderr) { 9147c478bd9Sstevel@tonic-gate (void) t_free((char *)uderr, T_UDERROR); 9157c478bd9Sstevel@tonic-gate uderr = NULL; 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * Allocate a unitdata structure for receiving the event. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate if (unitdata == NULL) { 9237c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 9247c478bd9Sstevel@tonic-gate unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL); 9257c478bd9Sstevel@tonic-gate if (unitdata == NULL) { 9267c478bd9Sstevel@tonic-gate if (t_errno == TSYSERR) { 9277c478bd9Sstevel@tonic-gate /* 9287c478bd9Sstevel@tonic-gate * Save the error code across 9297c478bd9Sstevel@tonic-gate * syslog(), just in case 9307c478bd9Sstevel@tonic-gate * syslog() gets its own error 9317c478bd9Sstevel@tonic-gate * and therefore overwrites errno. 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate error = errno; 9347c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 9357c478bd9Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m", 9367c478bd9Sstevel@tonic-gate fd, nconf->nc_proto); 9377c478bd9Sstevel@tonic-gate return (error); 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 9407c478bd9Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d", 9417c478bd9Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 9427c478bd9Sstevel@tonic-gate goto flush_it; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate try_again: 9477c478bd9Sstevel@tonic-gate flags = 0; 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate /* 9507c478bd9Sstevel@tonic-gate * The idea is we wait for T_UNITDATA_IND's. Of course, 9517c478bd9Sstevel@tonic-gate * we don't get any, because rpcmod filters them out. 9527c478bd9Sstevel@tonic-gate * However, we need to call t_rcvudata() to let TLI 9537c478bd9Sstevel@tonic-gate * tell us we have a T_UDERROR_IND. 9547c478bd9Sstevel@tonic-gate * 9557c478bd9Sstevel@tonic-gate * algorithm is: 9567c478bd9Sstevel@tonic-gate * t_rcvudata(), expecting TLOOK. 9577c478bd9Sstevel@tonic-gate * t_look(), expecting T_UDERR. 9587c478bd9Sstevel@tonic-gate * t_rcvuderr(), expecting success (0). 9597c478bd9Sstevel@tonic-gate * expand destination address into ASCII, 9607c478bd9Sstevel@tonic-gate * and dump it. 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate ret = t_rcvudata(fd, unitdata, &flags); 9647c478bd9Sstevel@tonic-gate if (ret == 0 || t_errno == TBUFOVFLW) { 9657c478bd9Sstevel@tonic-gate (void) syslog(LOG_WARNING, 9667c478bd9Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes", 9677c478bd9Sstevel@tonic-gate fd, nconf->nc_proto, unitdata->udata.len); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * Even though we don't expect any data, in case we do, 9717c478bd9Sstevel@tonic-gate * keep reading until there is no more. 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate if (flags & T_MORE) 9747c478bd9Sstevel@tonic-gate goto try_again; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate return (0); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate switch (t_errno) { 9807c478bd9Sstevel@tonic-gate case TNODATA: 9817c478bd9Sstevel@tonic-gate return (0); 9827c478bd9Sstevel@tonic-gate case TSYSERR: 9837c478bd9Sstevel@tonic-gate /* 9847c478bd9Sstevel@tonic-gate * System errors are returned to caller. 9857c478bd9Sstevel@tonic-gate * Save the error code across 9867c478bd9Sstevel@tonic-gate * syslog(), just in case 9877c478bd9Sstevel@tonic-gate * syslog() gets its own error 9887c478bd9Sstevel@tonic-gate * and therefore overwrites errno. 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate error = errno; 9917c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 9927c478bd9Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) %m", 9937c478bd9Sstevel@tonic-gate fd, nconf->nc_proto); 9947c478bd9Sstevel@tonic-gate return (error); 9957c478bd9Sstevel@tonic-gate case TLOOK: 9967c478bd9Sstevel@tonic-gate break; 9977c478bd9Sstevel@tonic-gate default: 9987c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 9997c478bd9Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) TLI error %d", 10007c478bd9Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 10017c478bd9Sstevel@tonic-gate goto flush_it; 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate ret = t_look(fd); 10057c478bd9Sstevel@tonic-gate switch (ret) { 10067c478bd9Sstevel@tonic-gate case 0: 10077c478bd9Sstevel@tonic-gate return (0); 10087c478bd9Sstevel@tonic-gate case -1: 10097c478bd9Sstevel@tonic-gate /* 10107c478bd9Sstevel@tonic-gate * System errors are returned to caller. 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate if (t_errno == TSYSERR) { 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * Save the error code across 10157c478bd9Sstevel@tonic-gate * syslog(), just in case 10167c478bd9Sstevel@tonic-gate * syslog() gets its own error 10177c478bd9Sstevel@tonic-gate * and therefore overwrites errno. 10187c478bd9Sstevel@tonic-gate */ 10197c478bd9Sstevel@tonic-gate error = errno; 10207c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 10217c478bd9Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) %m", 10227c478bd9Sstevel@tonic-gate fd, nconf->nc_proto); 10237c478bd9Sstevel@tonic-gate return (error); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 10267c478bd9Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) TLI error %d", 10277c478bd9Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 10287c478bd9Sstevel@tonic-gate goto flush_it; 10297c478bd9Sstevel@tonic-gate case T_UDERR: 10307c478bd9Sstevel@tonic-gate break; 10317c478bd9Sstevel@tonic-gate default: 10327c478bd9Sstevel@tonic-gate (void) syslog(LOG_WARNING, 10337c478bd9Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)", 10347c478bd9Sstevel@tonic-gate fd, nconf->nc_proto, ret, T_UDERR); 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate if (uderr == NULL) { 10387c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 10397c478bd9Sstevel@tonic-gate uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL); 10407c478bd9Sstevel@tonic-gate if (uderr == NULL) { 10417c478bd9Sstevel@tonic-gate if (t_errno == TSYSERR) { 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * Save the error code across 10447c478bd9Sstevel@tonic-gate * syslog(), just in case 10457c478bd9Sstevel@tonic-gate * syslog() gets its own error 10467c478bd9Sstevel@tonic-gate * and therefore overwrites errno. 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate error = errno; 10497c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 10507c478bd9Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m", 10517c478bd9Sstevel@tonic-gate fd, nconf->nc_proto); 10527c478bd9Sstevel@tonic-gate return (error); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 10557c478bd9Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d", 10567c478bd9Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 10577c478bd9Sstevel@tonic-gate goto flush_it; 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate ret = t_rcvuderr(fd, uderr); 10627c478bd9Sstevel@tonic-gate if (ret == 0) { 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate /* 10657c478bd9Sstevel@tonic-gate * Save the datagram error in errno, so that the 10667c478bd9Sstevel@tonic-gate * %m argument to syslog picks up the error string. 10677c478bd9Sstevel@tonic-gate */ 10687c478bd9Sstevel@tonic-gate errno = uderr->error; 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * Log the datagram error, then log the host that 10727c478bd9Sstevel@tonic-gate * probably triggerred. Cannot log both in the 10737c478bd9Sstevel@tonic-gate * same transaction because of packet size limitations 10747c478bd9Sstevel@tonic-gate * in /dev/log. 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 10777c478bd9Sstevel@tonic-gate "NFS response over <file descriptor %d/transport %s> generated error: %m", 10787c478bd9Sstevel@tonic-gate fd, nconf->nc_proto); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * Try to map the client's address back to a 10827c478bd9Sstevel@tonic-gate * name. 10837c478bd9Sstevel@tonic-gate */ 10847c478bd9Sstevel@tonic-gate ret = netdir_getbyaddr(nconf, &host, &uderr->addr); 10857c478bd9Sstevel@tonic-gate if (ret != -1 && host && host->h_cnt > 0 && 10867c478bd9Sstevel@tonic-gate host->h_hostservs) { 10877c478bd9Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 10887c478bd9Sstevel@tonic-gate "Bad NFS response was sent to client with host name: %s; service port: %s", 10897c478bd9Sstevel@tonic-gate host->h_hostservs->h_host, 10907c478bd9Sstevel@tonic-gate host->h_hostservs->h_serv); 10917c478bd9Sstevel@tonic-gate } else { 10927c478bd9Sstevel@tonic-gate int i, j; 10937c478bd9Sstevel@tonic-gate char *buf; 10947c478bd9Sstevel@tonic-gate char *hex = "0123456789abcdef"; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * Mapping failed, print the whole thing 10987c478bd9Sstevel@tonic-gate * in ASCII hex. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate buf = (char *)malloc(uderr->addr.len * 2 + 1); 11017c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) { 11027c478bd9Sstevel@tonic-gate buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf]; 11037c478bd9Sstevel@tonic-gate buf[j+1] = hex[uderr->addr.buf[i] & 0xf]; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate buf[j] = '\0'; 11067c478bd9Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 11077c478bd9Sstevel@tonic-gate "Bad NFS response was sent to client with transport address: 0x%s", 11087c478bd9Sstevel@tonic-gate buf); 11097c478bd9Sstevel@tonic-gate free((void *)buf); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate if (ret == 0 && host != NULL) 11137c478bd9Sstevel@tonic-gate netdir_free((void *)host, ND_HOSTSERVLIST); 11147c478bd9Sstevel@tonic-gate return (0); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate switch (t_errno) { 11187c478bd9Sstevel@tonic-gate case TNOUDERR: 11197c478bd9Sstevel@tonic-gate goto flush_it; 11207c478bd9Sstevel@tonic-gate case TSYSERR: 11217c478bd9Sstevel@tonic-gate /* 11227c478bd9Sstevel@tonic-gate * System errors are returned to caller. 11237c478bd9Sstevel@tonic-gate * Save the error code across 11247c478bd9Sstevel@tonic-gate * syslog(), just in case 11257c478bd9Sstevel@tonic-gate * syslog() gets its own error 11267c478bd9Sstevel@tonic-gate * and therefore overwrites errno. 11277c478bd9Sstevel@tonic-gate */ 11287c478bd9Sstevel@tonic-gate error = errno; 11297c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 11307c478bd9Sstevel@tonic-gate "t_rcvuderr(file descriptor %d/transport %s) %m", 11317c478bd9Sstevel@tonic-gate fd, nconf->nc_proto); 11327c478bd9Sstevel@tonic-gate return (error); 11337c478bd9Sstevel@tonic-gate default: 11347c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 11357c478bd9Sstevel@tonic-gate "t_rcvuderr(file descriptor %d/transport %s) TLI error %d", 11367c478bd9Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 11377c478bd9Sstevel@tonic-gate goto flush_it; 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate flush_it: 11417c478bd9Sstevel@tonic-gate /* 11427c478bd9Sstevel@tonic-gate * If we get here, then we could not cope with whatever message 11437c478bd9Sstevel@tonic-gate * we attempted to read, so flush it. If we did read a message, 11447c478bd9Sstevel@tonic-gate * and one isn't present, that is all right, because fd is in 11457c478bd9Sstevel@tonic-gate * nonblocking mode. 11467c478bd9Sstevel@tonic-gate */ 11477c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 11487c478bd9Sstevel@tonic-gate "Flushing one input message from <file descriptor %d/transport %s>", 11497c478bd9Sstevel@tonic-gate fd, nconf->nc_proto); 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate /* 11527c478bd9Sstevel@tonic-gate * Read and discard the message. Do this this until there is 11537c478bd9Sstevel@tonic-gate * no more control/data in the message or until we get an error. 11547c478bd9Sstevel@tonic-gate */ 11557c478bd9Sstevel@tonic-gate do { 11567c478bd9Sstevel@tonic-gate ctl->maxlen = sizeof (ctlbuf); 11577c478bd9Sstevel@tonic-gate ctl->buf = ctlbuf; 11587c478bd9Sstevel@tonic-gate data->maxlen = sizeof (databuf); 11597c478bd9Sstevel@tonic-gate data->buf = databuf; 11607c478bd9Sstevel@tonic-gate flags = 0; 11617c478bd9Sstevel@tonic-gate ret = getmsg(fd, ctl, data, &flags); 11627c478bd9Sstevel@tonic-gate if (ret == -1) 11637c478bd9Sstevel@tonic-gate return (errno); 11647c478bd9Sstevel@tonic-gate } while (ret != 0); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate return (0); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate static void 11707c478bd9Sstevel@tonic-gate conn_close_oldest(void) 11717c478bd9Sstevel@tonic-gate { 11727c478bd9Sstevel@tonic-gate int fd; 11737c478bd9Sstevel@tonic-gate int i1; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * Find the oldest connection that is not already in the 11777c478bd9Sstevel@tonic-gate * process of shutting down. 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate for (i1 = end_listen_fds; /* no conditional expression */; i1++) { 11807c478bd9Sstevel@tonic-gate if (i1 >= num_fds) 11817c478bd9Sstevel@tonic-gate return; 11827c478bd9Sstevel@tonic-gate if (conn_polled[i1].closing == 0) 11837c478bd9Sstevel@tonic-gate break; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate #ifdef DEBUG 11867c478bd9Sstevel@tonic-gate printf("too many connections (%d), releasing oldest (%d)\n", 11877c478bd9Sstevel@tonic-gate num_conns, poll_array[i1].fd); 11887c478bd9Sstevel@tonic-gate #else 11897c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)", 11907c478bd9Sstevel@tonic-gate num_conns, poll_array[i1].fd); 11917c478bd9Sstevel@tonic-gate #endif 11927c478bd9Sstevel@tonic-gate fd = poll_array[i1].fd; 11937c478bd9Sstevel@tonic-gate if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) { 11947c478bd9Sstevel@tonic-gate /* 11957c478bd9Sstevel@tonic-gate * For politeness, send a T_DISCON_REQ to the transport 11967c478bd9Sstevel@tonic-gate * provider. We close the stream anyway. 11977c478bd9Sstevel@tonic-gate */ 11987c478bd9Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0); 11997c478bd9Sstevel@tonic-gate num_conns--; 12007c478bd9Sstevel@tonic-gate remove_from_poll_list(fd); 12017c478bd9Sstevel@tonic-gate (void) t_close(fd); 12027c478bd9Sstevel@tonic-gate } else { 12037c478bd9Sstevel@tonic-gate /* 12047c478bd9Sstevel@tonic-gate * For orderly release, we do not close the stream 12057c478bd9Sstevel@tonic-gate * until the T_ORDREL_IND arrives to complete 12067c478bd9Sstevel@tonic-gate * the handshake. 12077c478bd9Sstevel@tonic-gate */ 12087c478bd9Sstevel@tonic-gate if (t_sndrel(fd) == 0) 12097c478bd9Sstevel@tonic-gate conn_polled[i1].closing = 1; 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate static boolean_t 12147c478bd9Sstevel@tonic-gate conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 12157c478bd9Sstevel@tonic-gate { 12167c478bd9Sstevel@tonic-gate struct conn_ind *conn; 12177c478bd9Sstevel@tonic-gate struct conn_ind *next_conn; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate conn = (struct conn_ind *)malloc(sizeof (*conn)); 12207c478bd9Sstevel@tonic-gate if (conn == NULL) { 12217c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "malloc for listen indication failed"); 12227c478bd9Sstevel@tonic-gate return (FALSE); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 12267c478bd9Sstevel@tonic-gate conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); 12277c478bd9Sstevel@tonic-gate if (conn->conn_call == NULL) { 12287c478bd9Sstevel@tonic-gate free((char *)conn); 12297c478bd9Sstevel@tonic-gate nfslib_log_tli_error("t_alloc", fd, nconf); 12307c478bd9Sstevel@tonic-gate return (FALSE); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate if (t_listen(fd, conn->conn_call) == -1) { 12347c478bd9Sstevel@tonic-gate nfslib_log_tli_error("t_listen", fd, nconf); 12357c478bd9Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL); 12367c478bd9Sstevel@tonic-gate free((char *)conn); 12377c478bd9Sstevel@tonic-gate return (FALSE); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate if (conn->conn_call->udata.len > 0) { 12417c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 12427c478bd9Sstevel@tonic-gate "rejecting inbound connection(%s) with %d bytes of connect data", 12437c478bd9Sstevel@tonic-gate nconf->nc_proto, conn->conn_call->udata.len); 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate conn->conn_call->udata.len = 0; 12467c478bd9Sstevel@tonic-gate (void) t_snddis(fd, conn->conn_call); 12477c478bd9Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL); 12487c478bd9Sstevel@tonic-gate free((char *)conn); 12497c478bd9Sstevel@tonic-gate return (FALSE); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate if ((next_conn = *connp) != NULL) { 12537c478bd9Sstevel@tonic-gate next_conn->conn_prev->conn_next = conn; 12547c478bd9Sstevel@tonic-gate conn->conn_next = next_conn; 12557c478bd9Sstevel@tonic-gate conn->conn_prev = next_conn->conn_prev; 12567c478bd9Sstevel@tonic-gate next_conn->conn_prev = conn; 12577c478bd9Sstevel@tonic-gate } else { 12587c478bd9Sstevel@tonic-gate conn->conn_next = conn; 12597c478bd9Sstevel@tonic-gate conn->conn_prev = conn; 12607c478bd9Sstevel@tonic-gate *connp = conn; 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate return (TRUE); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate static int 12667c478bd9Sstevel@tonic-gate discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 12677c478bd9Sstevel@tonic-gate { 12687c478bd9Sstevel@tonic-gate struct conn_ind *conn; 12697c478bd9Sstevel@tonic-gate struct t_discon discon; 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate discon.udata.buf = (char *)0; 12727c478bd9Sstevel@tonic-gate discon.udata.maxlen = 0; 12737c478bd9Sstevel@tonic-gate if (t_rcvdis(fd, &discon) == -1) { 12747c478bd9Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf); 12757c478bd9Sstevel@tonic-gate return (-1); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate conn = *connp; 12797c478bd9Sstevel@tonic-gate if (conn == NULL) 12807c478bd9Sstevel@tonic-gate return (0); 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate do { 12837c478bd9Sstevel@tonic-gate if (conn->conn_call->sequence == discon.sequence) { 12847c478bd9Sstevel@tonic-gate if (conn->conn_next == conn) 12857c478bd9Sstevel@tonic-gate *connp = (struct conn_ind *)0; 12867c478bd9Sstevel@tonic-gate else { 12877c478bd9Sstevel@tonic-gate if (conn == *connp) { 12887c478bd9Sstevel@tonic-gate *connp = conn->conn_next; 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate conn->conn_next->conn_prev = conn->conn_prev; 12917c478bd9Sstevel@tonic-gate conn->conn_prev->conn_next = conn->conn_next; 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate free((char *)conn); 12947c478bd9Sstevel@tonic-gate break; 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate conn = conn->conn_next; 12977c478bd9Sstevel@tonic-gate } while (conn != *connp); 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate return (0); 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate static void 13037c478bd9Sstevel@tonic-gate cots_listen_event(int fd, int conn_index) 13047c478bd9Sstevel@tonic-gate { 13057c478bd9Sstevel@tonic-gate struct t_call *call; 13067c478bd9Sstevel@tonic-gate struct conn_ind *conn; 13077c478bd9Sstevel@tonic-gate struct conn_ind *conn_head; 13087c478bd9Sstevel@tonic-gate int event; 13097c478bd9Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc; 13107c478bd9Sstevel@tonic-gate int new_fd; 13117c478bd9Sstevel@tonic-gate struct netbuf addrmask; 13127c478bd9Sstevel@tonic-gate int ret = 0; 13137c478bd9Sstevel@tonic-gate char *clnt; 13147c478bd9Sstevel@tonic-gate char *clnt_uaddr = NULL; 13157c478bd9Sstevel@tonic-gate struct nd_hostservlist *clnt_serv = NULL; 13167c478bd9Sstevel@tonic-gate 131755393845SMarcel Telka conn_head = NULL; 13187c478bd9Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head); 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate while ((conn = conn_head) != NULL) { 13217c478bd9Sstevel@tonic-gate conn_head = conn->conn_next; 13227c478bd9Sstevel@tonic-gate if (conn_head == conn) 132355393845SMarcel Telka conn_head = NULL; 13247c478bd9Sstevel@tonic-gate else { 13257c478bd9Sstevel@tonic-gate conn_head->conn_prev = conn->conn_prev; 13267c478bd9Sstevel@tonic-gate conn->conn_prev->conn_next = conn_head; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate call = conn->conn_call; 132955393845SMarcel Telka free(conn); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate /* 13327c478bd9Sstevel@tonic-gate * If we have already accepted the maximum number of 13337c478bd9Sstevel@tonic-gate * connections allowed on the command line, then drop 13347c478bd9Sstevel@tonic-gate * the oldest connection (for any protocol) before 13357c478bd9Sstevel@tonic-gate * accepting the new connection. Unless explicitly 13367c478bd9Sstevel@tonic-gate * set on the command line, max_conns_allowed is -1. 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate if (max_conns_allowed != -1 && num_conns >= max_conns_allowed) 13397c478bd9Sstevel@tonic-gate conn_close_oldest(); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * Create a new transport endpoint for the same proto as 13437c478bd9Sstevel@tonic-gate * the listener. 13447c478bd9Sstevel@tonic-gate */ 13457c478bd9Sstevel@tonic-gate new_fd = nfslib_transport_open(nconf); 13467c478bd9Sstevel@tonic-gate if (new_fd == -1) { 13477c478bd9Sstevel@tonic-gate call->udata.len = 0; 13487c478bd9Sstevel@tonic-gate (void) t_snddis(fd, call); 13497c478bd9Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 13507c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot establish transport over %s", 13517c478bd9Sstevel@tonic-gate nconf->nc_device); 13527c478bd9Sstevel@tonic-gate continue; 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate /* Bind to a generic address/port for the accepting stream. */ 135655393845SMarcel Telka if (t_bind(new_fd, NULL, NULL) == -1) { 13577c478bd9Sstevel@tonic-gate nfslib_log_tli_error("t_bind", new_fd, nconf); 13587c478bd9Sstevel@tonic-gate call->udata.len = 0; 13597c478bd9Sstevel@tonic-gate (void) t_snddis(fd, call); 13607c478bd9Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 13617c478bd9Sstevel@tonic-gate (void) t_close(new_fd); 13627c478bd9Sstevel@tonic-gate continue; 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate while (t_accept(fd, new_fd, call) == -1) { 13667c478bd9Sstevel@tonic-gate if (t_errno != TLOOK) { 13677c478bd9Sstevel@tonic-gate #ifdef DEBUG 13687c478bd9Sstevel@tonic-gate nfslib_log_tli_error("t_accept", fd, nconf); 13697c478bd9Sstevel@tonic-gate #endif 13707c478bd9Sstevel@tonic-gate call->udata.len = 0; 13717c478bd9Sstevel@tonic-gate (void) t_snddis(fd, call); 13727c478bd9Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 13737c478bd9Sstevel@tonic-gate (void) t_close(new_fd); 13747c478bd9Sstevel@tonic-gate goto do_next_conn; 13757c478bd9Sstevel@tonic-gate } 13767c478bd9Sstevel@tonic-gate while (event = t_look(fd)) { 13777c478bd9Sstevel@tonic-gate switch (event) { 13787c478bd9Sstevel@tonic-gate case T_LISTEN: 13797c478bd9Sstevel@tonic-gate #ifdef DEBUG 13807c478bd9Sstevel@tonic-gate printf( 13817c478bd9Sstevel@tonic-gate "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto); 13827c478bd9Sstevel@tonic-gate #endif 13837c478bd9Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head); 13847c478bd9Sstevel@tonic-gate continue; 13857c478bd9Sstevel@tonic-gate case T_DISCONNECT: 13867c478bd9Sstevel@tonic-gate #ifdef DEBUG 13877c478bd9Sstevel@tonic-gate printf( 13887c478bd9Sstevel@tonic-gate "cots_listen_event(%s): T_DISCONNECT during accept processing\n", 13897c478bd9Sstevel@tonic-gate nconf->nc_proto); 13907c478bd9Sstevel@tonic-gate #endif 13917c478bd9Sstevel@tonic-gate (void) discon_get(fd, nconf, 13927c478bd9Sstevel@tonic-gate &conn_head); 13937c478bd9Sstevel@tonic-gate continue; 13947c478bd9Sstevel@tonic-gate default: 13957c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 13967c478bd9Sstevel@tonic-gate "unexpected event 0x%x during accept processing (%s)", 13977c478bd9Sstevel@tonic-gate event, nconf->nc_proto); 13987c478bd9Sstevel@tonic-gate call->udata.len = 0; 13997c478bd9Sstevel@tonic-gate (void) t_snddis(fd, call); 14007c478bd9Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 14017c478bd9Sstevel@tonic-gate (void) t_close(new_fd); 14027c478bd9Sstevel@tonic-gate goto do_next_conn; 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate if (set_addrmask(new_fd, nconf, &addrmask) < 0) { 14087c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, 14097c478bd9Sstevel@tonic-gate "Cannot set address mask for %s", 14107c478bd9Sstevel@tonic-gate nconf->nc_netid); 141155393845SMarcel Telka (void) t_snddis(new_fd, NULL); 141255393845SMarcel Telka (void) t_free((char *)call, T_CALL); 141355393845SMarcel Telka (void) t_close(new_fd); 141455393845SMarcel Telka continue; 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 141755393845SMarcel Telka /* Tell kRPC about the new stream. */ 14187c478bd9Sstevel@tonic-gate if (Mysvc4 != NULL) 14197c478bd9Sstevel@tonic-gate ret = (*Mysvc4)(new_fd, &addrmask, nconf, 14207c478bd9Sstevel@tonic-gate NFS4_KRPC_START, &call->addr); 14217c478bd9Sstevel@tonic-gate else 14227c478bd9Sstevel@tonic-gate ret = (*Mysvc)(new_fd, addrmask, nconf); 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate if (ret < 0) { 14257c478bd9Sstevel@tonic-gate if (errno != ENOTCONN) { 14267c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 14277c478bd9Sstevel@tonic-gate "unable to register new connection: %m"); 14287c478bd9Sstevel@tonic-gate } else { 14297c478bd9Sstevel@tonic-gate /* 14307c478bd9Sstevel@tonic-gate * This is the only error that could be 14317c478bd9Sstevel@tonic-gate * caused by the client, so who was it? 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate if (netdir_getbyaddr(nconf, &clnt_serv, 14347c478bd9Sstevel@tonic-gate &(call->addr)) == ND_OK && 14357c478bd9Sstevel@tonic-gate clnt_serv->h_cnt > 0) 14367c478bd9Sstevel@tonic-gate clnt = clnt_serv->h_hostservs->h_host; 14377c478bd9Sstevel@tonic-gate else 14387c478bd9Sstevel@tonic-gate clnt = clnt_uaddr = taddr2uaddr(nconf, 14397c478bd9Sstevel@tonic-gate &(call->addr)); 14407c478bd9Sstevel@tonic-gate /* 14417c478bd9Sstevel@tonic-gate * If we don't know who the client was, 14427c478bd9Sstevel@tonic-gate * remain silent. 14437c478bd9Sstevel@tonic-gate */ 14447c478bd9Sstevel@tonic-gate if (clnt) 14457c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 14467c478bd9Sstevel@tonic-gate "unable to register new connection: client %s has dropped connection", clnt); 144755393845SMarcel Telka if (clnt_serv) { 14487c478bd9Sstevel@tonic-gate netdir_free(clnt_serv, ND_HOSTSERVLIST); 144955393845SMarcel Telka clnt_serv = NULL; 145055393845SMarcel Telka } 145155393845SMarcel Telka if (clnt_uaddr) { 14527c478bd9Sstevel@tonic-gate free(clnt_uaddr); 145355393845SMarcel Telka clnt_uaddr = NULL; 145455393845SMarcel Telka } 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate free(addrmask.buf); 145755393845SMarcel Telka (void) t_snddis(new_fd, NULL); 14587c478bd9Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 14597c478bd9Sstevel@tonic-gate (void) t_close(new_fd); 14607c478bd9Sstevel@tonic-gate goto do_next_conn; 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate free(addrmask.buf); 14647c478bd9Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate /* 14677c478bd9Sstevel@tonic-gate * Poll on the new descriptor so that we get disconnect 14687c478bd9Sstevel@tonic-gate * and orderly release indications. 14697c478bd9Sstevel@tonic-gate */ 14707c478bd9Sstevel@tonic-gate num_conns++; 14717c478bd9Sstevel@tonic-gate add_to_poll_list(new_fd, nconf); 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate /* Reset nconf in case it has been moved. */ 14747c478bd9Sstevel@tonic-gate nconf = &conn_polled[conn_index].nc; 14757c478bd9Sstevel@tonic-gate do_next_conn:; 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate static int 14807c478bd9Sstevel@tonic-gate do_poll_cots_action(int fd, int conn_index) 14817c478bd9Sstevel@tonic-gate { 14827c478bd9Sstevel@tonic-gate char buf[256]; 14837c478bd9Sstevel@tonic-gate int event; 14847c478bd9Sstevel@tonic-gate int i1; 14857c478bd9Sstevel@tonic-gate int flags; 14867c478bd9Sstevel@tonic-gate struct conn_entry *connent = &conn_polled[conn_index]; 14877c478bd9Sstevel@tonic-gate struct netconfig *nconf = &(connent->nc); 14887c478bd9Sstevel@tonic-gate const char *errorstr; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate while (event = t_look(fd)) { 14917c478bd9Sstevel@tonic-gate switch (event) { 14927c478bd9Sstevel@tonic-gate case T_LISTEN: 14937c478bd9Sstevel@tonic-gate #ifdef DEBUG 14947c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd); 14957c478bd9Sstevel@tonic-gate #endif 14967c478bd9Sstevel@tonic-gate cots_listen_event(fd, conn_index); 14977c478bd9Sstevel@tonic-gate break; 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate case T_DATA: 15007c478bd9Sstevel@tonic-gate #ifdef DEBUG 15017c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto); 15027c478bd9Sstevel@tonic-gate #endif 15037c478bd9Sstevel@tonic-gate /* 15047c478bd9Sstevel@tonic-gate * Receive a private notification from CONS rpcmod. 15057c478bd9Sstevel@tonic-gate */ 15067c478bd9Sstevel@tonic-gate i1 = t_rcv(fd, buf, sizeof (buf), &flags); 15077c478bd9Sstevel@tonic-gate if (i1 == -1) { 15087c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "t_rcv failed"); 15097c478bd9Sstevel@tonic-gate break; 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate if (i1 < sizeof (int)) 15127c478bd9Sstevel@tonic-gate break; 15137c478bd9Sstevel@tonic-gate i1 = BE32_TO_U32(buf); 15147c478bd9Sstevel@tonic-gate if (i1 == 1 || i1 == 2) { 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * This connection has been idle for too long, 15177c478bd9Sstevel@tonic-gate * so release it as politely as we can. If we 15187c478bd9Sstevel@tonic-gate * have already initiated an orderly release 15197c478bd9Sstevel@tonic-gate * and we get notified that the stream is 15207c478bd9Sstevel@tonic-gate * still idle, pull the plug. This prevents 15217c478bd9Sstevel@tonic-gate * hung connections from continuing to consume 15227c478bd9Sstevel@tonic-gate * resources. 15237c478bd9Sstevel@tonic-gate */ 15247c478bd9Sstevel@tonic-gate #ifdef DEBUG 15257c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd); 15267c478bd9Sstevel@tonic-gate printf("initiating orderly release of idle connection\n"); 15277c478bd9Sstevel@tonic-gate #endif 15287c478bd9Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_COTS || 15297c478bd9Sstevel@tonic-gate connent->closing != 0) { 15307c478bd9Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0); 15317c478bd9Sstevel@tonic-gate goto fdclose; 15327c478bd9Sstevel@tonic-gate } 15337c478bd9Sstevel@tonic-gate /* 15347c478bd9Sstevel@tonic-gate * For NC_TPI_COTS_ORD, the stream is closed 15357c478bd9Sstevel@tonic-gate * and removed from the poll list when the 15367c478bd9Sstevel@tonic-gate * T_ORDREL is received from the provider. We 15377c478bd9Sstevel@tonic-gate * don't wait for it here because it may take 15387c478bd9Sstevel@tonic-gate * a while for the transport to shut down. 15397c478bd9Sstevel@tonic-gate */ 15407c478bd9Sstevel@tonic-gate if (t_sndrel(fd) == -1) { 15417c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 15427c478bd9Sstevel@tonic-gate "unable to send orderly release %m"); 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate connent->closing = 1; 15457c478bd9Sstevel@tonic-gate } else 15467c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 15477c478bd9Sstevel@tonic-gate "unexpected event from CONS rpcmod %d", i1); 15487c478bd9Sstevel@tonic-gate break; 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate case T_ORDREL: 15517c478bd9Sstevel@tonic-gate #ifdef DEBUG 15527c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd); 15537c478bd9Sstevel@tonic-gate #endif 15547c478bd9Sstevel@tonic-gate /* Perform an orderly release. */ 15557c478bd9Sstevel@tonic-gate if (t_rcvrel(fd) == 0) { 15567c478bd9Sstevel@tonic-gate /* T_ORDREL on listen fd's should be ignored */ 15577c478bd9Sstevel@tonic-gate if (!is_listen_fd_index(conn_index)) { 15587c478bd9Sstevel@tonic-gate (void) t_sndrel(fd); 15597c478bd9Sstevel@tonic-gate goto fdclose; 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate break; 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate } else if (t_errno == TLOOK) { 15647c478bd9Sstevel@tonic-gate break; 15657c478bd9Sstevel@tonic-gate } else { 15667c478bd9Sstevel@tonic-gate nfslib_log_tli_error("t_rcvrel", fd, nconf); 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate /* 15697c478bd9Sstevel@tonic-gate * check to make sure we do not close 15707c478bd9Sstevel@tonic-gate * listen fd 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate if (is_listen_fd_index(conn_index)) 15737c478bd9Sstevel@tonic-gate break; 15747c478bd9Sstevel@tonic-gate else 15757c478bd9Sstevel@tonic-gate goto fdclose; 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate case T_DISCONNECT: 15797c478bd9Sstevel@tonic-gate #ifdef DEBUG 15807c478bd9Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd); 15817c478bd9Sstevel@tonic-gate #endif 15827c478bd9Sstevel@tonic-gate if (t_rcvdis(fd, (struct t_discon *)NULL) == -1) 15837c478bd9Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf); 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * T_DISCONNECT on listen fd's should be ignored. 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate if (is_listen_fd_index(conn_index)) 15897c478bd9Sstevel@tonic-gate break; 15907c478bd9Sstevel@tonic-gate else 15917c478bd9Sstevel@tonic-gate goto fdclose; 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate default: 1594*09b0d01cSGary Mills if (t_errno == TSYSERR) { 15957c478bd9Sstevel@tonic-gate if ((errorstr = strerror(errno)) == NULL) { 1596e810a982Svv149972 (void) sprintf(buf, 1597e810a982Svv149972 "Unknown error num %d", errno); 15987c478bd9Sstevel@tonic-gate errorstr = (const char *) buf; 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate } else if (event == -1) 16017c478bd9Sstevel@tonic-gate errorstr = t_strerror(t_errno); 16027c478bd9Sstevel@tonic-gate else 16037c478bd9Sstevel@tonic-gate errorstr = ""; 16047c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 16057c478bd9Sstevel@tonic-gate "unexpected TLI event (0x%x) on " 16067c478bd9Sstevel@tonic-gate "connection-oriented transport(%s,%d):%s", 16077c478bd9Sstevel@tonic-gate event, nconf->nc_proto, fd, errorstr); 16087c478bd9Sstevel@tonic-gate fdclose: 16097c478bd9Sstevel@tonic-gate num_conns--; 16107c478bd9Sstevel@tonic-gate remove_from_poll_list(fd); 16117c478bd9Sstevel@tonic-gate (void) t_close(fd); 16127c478bd9Sstevel@tonic-gate return (0); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate return (0); 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate static char * 16207c478bd9Sstevel@tonic-gate serv_name_to_port_name(char *name) 16217c478bd9Sstevel@tonic-gate { 16227c478bd9Sstevel@tonic-gate /* 16237c478bd9Sstevel@tonic-gate * Map service names (used primarily in logging) to 16247c478bd9Sstevel@tonic-gate * RPC port names (used by netdir_*() routines). 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate if (strcmp(name, "NFS") == 0) { 16277c478bd9Sstevel@tonic-gate return ("nfs"); 16287c478bd9Sstevel@tonic-gate } else if (strcmp(name, "NLM") == 0) { 16297c478bd9Sstevel@tonic-gate return ("lockd"); 16307c478bd9Sstevel@tonic-gate } else if (strcmp(name, "NFS4_CALLBACK") == 0) { 16317c478bd9Sstevel@tonic-gate return ("nfs4_callback"); 16327c478bd9Sstevel@tonic-gate } 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate return ("unrecognized"); 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate static int 16387c478bd9Sstevel@tonic-gate bind_to_provider(char *provider, char *serv, struct netbuf **addr, 16397c478bd9Sstevel@tonic-gate struct netconfig **retnconf) 16407c478bd9Sstevel@tonic-gate { 16417c478bd9Sstevel@tonic-gate struct netconfig *nconf; 16427c478bd9Sstevel@tonic-gate NCONF_HANDLE *nc; 16437c478bd9Sstevel@tonic-gate struct nd_hostserv hs; 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate hs.h_host = HOST_SELF; 16467c478bd9Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv); 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 16497c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 16507c478bd9Sstevel@tonic-gate return (-1); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 16537c478bd9Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) && 16547c478bd9Sstevel@tonic-gate strcmp(nconf->nc_device, provider) == 0) { 16557c478bd9Sstevel@tonic-gate *retnconf = nconf; 16567c478bd9Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs, 16577c478bd9Sstevel@tonic-gate listen_backlog)); 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate } 16607c478bd9Sstevel@tonic-gate (void) endnetconfig(nc); 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for provider %s", 16637c478bd9Sstevel@tonic-gate provider); 16647c478bd9Sstevel@tonic-gate return (-1); 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate static int 16687c478bd9Sstevel@tonic-gate bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr, 16697c478bd9Sstevel@tonic-gate struct netconfig **retnconf) 16707c478bd9Sstevel@tonic-gate { 16717c478bd9Sstevel@tonic-gate struct netconfig *nconf; 16727c478bd9Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 16737c478bd9Sstevel@tonic-gate struct nd_hostserv hs; 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate hs.h_host = HOST_SELF; 16767c478bd9Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv); 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 16797c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 16807c478bd9Sstevel@tonic-gate return (-1); 16817c478bd9Sstevel@tonic-gate } 16827c478bd9Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 16837c478bd9Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) { 16847c478bd9Sstevel@tonic-gate *retnconf = nconf; 16857c478bd9Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs, 16867c478bd9Sstevel@tonic-gate listen_backlog)); 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate (void) endnetconfig(nc); 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s", 16927c478bd9Sstevel@tonic-gate proto); 16937c478bd9Sstevel@tonic-gate return (-1); 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate #include <netinet/in.h> 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate /* 16997c478bd9Sstevel@tonic-gate * Create an address mask appropriate for the transport. 17007c478bd9Sstevel@tonic-gate * The mask is used to obtain the host-specific part of 17017c478bd9Sstevel@tonic-gate * a network address when comparing addresses. 17027c478bd9Sstevel@tonic-gate * For an internet address the host-specific part is just 17037c478bd9Sstevel@tonic-gate * the 32 bit IP address and this part of the mask is set 17047c478bd9Sstevel@tonic-gate * to all-ones. The port number part of the mask is zeroes. 17057c478bd9Sstevel@tonic-gate */ 17067c478bd9Sstevel@tonic-gate static int 1707bbaa8b60SDan Kruchinin set_addrmask(int fd, 1708bbaa8b60SDan Kruchinin struct netconfig *nconf, 1709bbaa8b60SDan Kruchinin struct netbuf *mask) 17107c478bd9Sstevel@tonic-gate { 17117c478bd9Sstevel@tonic-gate struct t_info info; 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate /* 17147c478bd9Sstevel@tonic-gate * Find the size of the address we need to mask. 17157c478bd9Sstevel@tonic-gate */ 17167c478bd9Sstevel@tonic-gate if (t_getinfo(fd, &info) < 0) { 17177c478bd9Sstevel@tonic-gate t_error("t_getinfo"); 17187c478bd9Sstevel@tonic-gate return (-1); 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate mask->len = mask->maxlen = info.addr; 17217c478bd9Sstevel@tonic-gate if (info.addr <= 0) { 17224a030418SDan Kruchinin /* 17234a030418SDan Kruchinin * loopback devices have infinite addr size 17244a030418SDan Kruchinin * (it is identified by -1 in addr field of t_info structure), 17254a030418SDan Kruchinin * so don't build the netmask for them. It's a special case 17264a030418SDan Kruchinin * that should be handled properly. 17274a030418SDan Kruchinin */ 17284a030418SDan Kruchinin if ((info.addr == -1) && 17294a030418SDan Kruchinin (0 == strcmp(nconf->nc_protofmly, NC_LOOPBACK))) { 17304a030418SDan Kruchinin memset(mask, 0, sizeof (*mask)); 17314a030418SDan Kruchinin return (0); 17324a030418SDan Kruchinin } 17334a030418SDan Kruchinin 1734bbaa8b60SDan Kruchinin syslog(LOG_ERR, "set_addrmask: address size: %ld", info.addr); 17357c478bd9Sstevel@tonic-gate return (-1); 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate mask->buf = (char *)malloc(mask->len); 17397c478bd9Sstevel@tonic-gate if (mask->buf == NULL) { 17407c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "set_addrmask: no memory"); 17417c478bd9Sstevel@tonic-gate return (-1); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */ 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 17467c478bd9Sstevel@tonic-gate /* 17477c478bd9Sstevel@tonic-gate * Set the mask so that the port is ignored. 17487c478bd9Sstevel@tonic-gate */ 17497c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 17507c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr = 17517c478bd9Sstevel@tonic-gate (ulong_t)~0; 17527c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 17537c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_family = 17547c478bd9Sstevel@tonic-gate (ushort_t)~0; 17557c478bd9Sstevel@tonic-gate } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 17567c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 17577c478bd9Sstevel@tonic-gate (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr, 17587c478bd9Sstevel@tonic-gate (uchar_t)~0, sizeof (struct in6_addr)); 17597c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 17607c478bd9Sstevel@tonic-gate ((struct sockaddr_in6 *)mask->buf)->sin6_family = 17617c478bd9Sstevel@tonic-gate (ushort_t)~0; 17627c478bd9Sstevel@tonic-gate } else { 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate /* 17657c478bd9Sstevel@tonic-gate * Set all mask bits. 17667c478bd9Sstevel@tonic-gate */ 17677c478bd9Sstevel@tonic-gate (void) memset(mask->buf, 0xFF, mask->len); 17687c478bd9Sstevel@tonic-gate } 17697c478bd9Sstevel@tonic-gate return (0); 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate /* 17737c478bd9Sstevel@tonic-gate * For listen fd's index is always less than end_listen_fds. 17747c478bd9Sstevel@tonic-gate * end_listen_fds is defined externally in the daemon that uses this library. 17757c478bd9Sstevel@tonic-gate * It's value is equal to the number of open file descriptors after the 17767c478bd9Sstevel@tonic-gate * last listen end point was opened but before any connection was accepted. 17777c478bd9Sstevel@tonic-gate */ 17787c478bd9Sstevel@tonic-gate static int 17797c478bd9Sstevel@tonic-gate is_listen_fd_index(int index) 17807c478bd9Sstevel@tonic-gate { 17817c478bd9Sstevel@tonic-gate return (index < end_listen_fds); 17827c478bd9Sstevel@tonic-gate } 1783