10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51676Sjpk * Common Development and Distribution License (the "License").
61676Sjpk * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12648SSurya.Prakki@Sun.COM * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate * nfs_tbind.c, common part for nfsd and lockd.
270Sstevel@tonic-gate */
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <tiuser.h>
300Sstevel@tonic-gate #include <fcntl.h>
310Sstevel@tonic-gate #include <netconfig.h>
320Sstevel@tonic-gate #include <stropts.h>
330Sstevel@tonic-gate #include <errno.h>
340Sstevel@tonic-gate #include <syslog.h>
350Sstevel@tonic-gate #include <rpc/rpc.h>
360Sstevel@tonic-gate #include <sys/time.h>
370Sstevel@tonic-gate #include <sys/resource.h>
380Sstevel@tonic-gate #include <signal.h>
390Sstevel@tonic-gate #include <netdir.h>
400Sstevel@tonic-gate #include <unistd.h>
410Sstevel@tonic-gate #include <string.h>
420Sstevel@tonic-gate #include <netinet/tcp.h>
430Sstevel@tonic-gate #include <malloc.h>
440Sstevel@tonic-gate #include <stdlib.h>
450Sstevel@tonic-gate #include "nfs_tbind.h"
460Sstevel@tonic-gate #include <nfs/nfs.h>
470Sstevel@tonic-gate #include <nfs/nfs_acl.h>
480Sstevel@tonic-gate #include <nfs/nfssys.h>
490Sstevel@tonic-gate #include <nfs/nfs4.h>
501676Sjpk #include <zone.h>
511676Sjpk #include <sys/socket.h>
521676Sjpk #include <tsol/label.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate * Determine valid semantics for most applications.
560Sstevel@tonic-gate */
570Sstevel@tonic-gate #define OK_TPI_TYPE(_nconf) \
580Sstevel@tonic-gate (_nconf->nc_semantics == NC_TPI_CLTS || \
590Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS || \
600Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS_ORD)
610Sstevel@tonic-gate
620Sstevel@tonic-gate #define BE32_TO_U32(a) \
630Sstevel@tonic-gate ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \
640Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \
650Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \
660Sstevel@tonic-gate ((ulong_t)((uchar_t *)a)[3] & 0xFF))
670Sstevel@tonic-gate
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate * Number of elements to add to the poll array on each allocation.
700Sstevel@tonic-gate */
710Sstevel@tonic-gate #define POLL_ARRAY_INC_SIZE 64
720Sstevel@tonic-gate
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate * Number of file descriptors by which the process soft limit may be
750Sstevel@tonic-gate * increased on each call to nofile_increase(0).
760Sstevel@tonic-gate */
770Sstevel@tonic-gate #define NOFILE_INC_SIZE 64
780Sstevel@tonic-gate
7910004Sdai.ngo@sun.com /*
8010004Sdai.ngo@sun.com * Default TCP send and receive buffer size of NFS server.
8110004Sdai.ngo@sun.com */
8210004Sdai.ngo@sun.com #define NFSD_TCP_BUFSZ (1024*1024)
8310004Sdai.ngo@sun.com
840Sstevel@tonic-gate struct conn_ind {
850Sstevel@tonic-gate struct conn_ind *conn_next;
860Sstevel@tonic-gate struct conn_ind *conn_prev;
870Sstevel@tonic-gate struct t_call *conn_call;
880Sstevel@tonic-gate };
890Sstevel@tonic-gate
900Sstevel@tonic-gate struct conn_entry {
910Sstevel@tonic-gate bool_t closing;
920Sstevel@tonic-gate struct netconfig nc;
930Sstevel@tonic-gate };
940Sstevel@tonic-gate
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate * this file contains transport routines common to nfsd and lockd
970Sstevel@tonic-gate */
980Sstevel@tonic-gate static int nofile_increase(int);
990Sstevel@tonic-gate static int reuseaddr(int);
1001676Sjpk static int recvucred(int);
1011676Sjpk static int anonmlp(int);
1020Sstevel@tonic-gate static void add_to_poll_list(int, struct netconfig *);
1030Sstevel@tonic-gate static char *serv_name_to_port_name(char *);
1040Sstevel@tonic-gate static int bind_to_proto(char *, char *, struct netbuf **,
1050Sstevel@tonic-gate struct netconfig **);
1060Sstevel@tonic-gate static int bind_to_provider(char *, char *, struct netbuf **,
1070Sstevel@tonic-gate struct netconfig **);
1080Sstevel@tonic-gate static void conn_close_oldest(void);
1090Sstevel@tonic-gate static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
1100Sstevel@tonic-gate static void cots_listen_event(int, int);
1110Sstevel@tonic-gate static int discon_get(int, struct netconfig *, struct conn_ind **);
1120Sstevel@tonic-gate static int do_poll_clts_action(int, int);
1130Sstevel@tonic-gate static int do_poll_cots_action(int, int);
1140Sstevel@tonic-gate static void remove_from_poll_list(int);
1150Sstevel@tonic-gate static int set_addrmask(int, struct netconfig *, struct netbuf *);
1160Sstevel@tonic-gate static int is_listen_fd_index(int);
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate static struct pollfd *poll_array;
1190Sstevel@tonic-gate static struct conn_entry *conn_polled;
1200Sstevel@tonic-gate static int num_conns; /* Current number of connections */
1210Sstevel@tonic-gate int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
1220Sstevel@tonic-gate struct netbuf *);
12310004Sdai.ngo@sun.com static int setopt(int fd, int level, int name, int value);
12410004Sdai.ngo@sun.com static int get_opt(int fd, int level, int name);
12510004Sdai.ngo@sun.com static void nfslib_set_sockbuf(int fd);
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate * Called to create and prepare a transport descriptor for in-kernel
1290Sstevel@tonic-gate * RPC service.
1300Sstevel@tonic-gate * Returns -1 on failure and a valid descriptor on success.
1310Sstevel@tonic-gate */
1320Sstevel@tonic-gate int
nfslib_transport_open(struct netconfig * nconf)1330Sstevel@tonic-gate nfslib_transport_open(struct netconfig *nconf)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate int fd;
1360Sstevel@tonic-gate struct strioctl strioc;
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate if ((nconf == (struct netconfig *)NULL) ||
1390Sstevel@tonic-gate (nconf->nc_device == (char *)NULL)) {
1400Sstevel@tonic-gate syslog(LOG_ERR, "no netconfig device");
1410Sstevel@tonic-gate return (-1);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate * Open the transport device.
1460Sstevel@tonic-gate */
1470Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
1480Sstevel@tonic-gate if (fd == -1) {
1490Sstevel@tonic-gate if (t_errno == TSYSERR && errno == EMFILE &&
1500Sstevel@tonic-gate (nofile_increase(0) == 0)) {
1510Sstevel@tonic-gate /* Try again with a higher NOFILE limit. */
1520Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR,
1537208Svv149972 (struct t_info *)NULL);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate if (fd == -1) {
1560Sstevel@tonic-gate syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m",
1570Sstevel@tonic-gate nconf->nc_device, t_errno);
1580Sstevel@tonic-gate return (-1);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate * Pop timod because the RPC module must be as close as possible
1640Sstevel@tonic-gate * to the transport.
1650Sstevel@tonic-gate */
1660Sstevel@tonic-gate if (ioctl(fd, I_POP, 0) < 0) {
1670Sstevel@tonic-gate syslog(LOG_ERR, "I_POP of timod failed: %m");
1680Sstevel@tonic-gate (void) t_close(fd);
1690Sstevel@tonic-gate return (-1);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate * Common code for CLTS and COTS transports
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
1760Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
1770Sstevel@tonic-gate (void) t_close(fd);
1780Sstevel@tonic-gate return (-1);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate strioc.ic_cmd = RPC_SERVER;
1820Sstevel@tonic-gate strioc.ic_dp = (char *)0;
1830Sstevel@tonic-gate strioc.ic_len = 0;
1840Sstevel@tonic-gate strioc.ic_timout = -1;
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate /* Tell rpcmod to act like a server stream. */
1870Sstevel@tonic-gate if (ioctl(fd, I_STR, &strioc) < 0) {
1880Sstevel@tonic-gate syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m");
1890Sstevel@tonic-gate (void) t_close(fd);
1900Sstevel@tonic-gate return (-1);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate * Re-push timod so that we will still be doing TLI
1950Sstevel@tonic-gate * operations on the descriptor.
1960Sstevel@tonic-gate */
1970Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "timod") < 0) {
1980Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of timod failed: %m");
1990Sstevel@tonic-gate (void) t_close(fd);
2000Sstevel@tonic-gate return (-1);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2037208Svv149972 /*
2047208Svv149972 * Enable options of returning the ip's for udp.
2057208Svv149972 */
2067208Svv149972 if (strcmp(nconf->nc_netid, "udp6") == 0)
2077208Svv149972 __rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1);
2087208Svv149972 else if (strcmp(nconf->nc_netid, "udp") == 0)
2097208Svv149972 __rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1);
2107208Svv149972
2110Sstevel@tonic-gate return (fd);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate static int
nofile_increase(int limit)2150Sstevel@tonic-gate nofile_increase(int limit)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate struct rlimit rl;
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
2200Sstevel@tonic-gate syslog(LOG_ERR, "getrlimit of NOFILE failed: %m");
2210Sstevel@tonic-gate return (-1);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate if (limit > 0)
2250Sstevel@tonic-gate rl.rlim_cur = limit;
2260Sstevel@tonic-gate else
2270Sstevel@tonic-gate rl.rlim_cur += NOFILE_INC_SIZE;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate if (rl.rlim_cur > rl.rlim_max &&
2300Sstevel@tonic-gate rl.rlim_max != RLIM_INFINITY)
2310Sstevel@tonic-gate rl.rlim_max = rl.rlim_cur;
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
2340Sstevel@tonic-gate syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m",
2357208Svv149972 rl.rlim_cur);
2360Sstevel@tonic-gate return (-1);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate return (0);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
24210004Sdai.ngo@sun.com static void
nfslib_set_sockbuf(int fd)24310004Sdai.ngo@sun.com nfslib_set_sockbuf(int fd)
24410004Sdai.ngo@sun.com {
24510004Sdai.ngo@sun.com int curval, val;
24610004Sdai.ngo@sun.com
24710004Sdai.ngo@sun.com val = NFSD_TCP_BUFSZ;
24810004Sdai.ngo@sun.com
24910004Sdai.ngo@sun.com curval = get_opt(fd, SOL_SOCKET, SO_SNDBUF);
25010004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Current SO_SNDBUF value is %d", curval);
25110004Sdai.ngo@sun.com if ((curval != -1) && (curval < val)) {
25210004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Set SO_SNDBUF option to %d", val);
25310004Sdai.ngo@sun.com if (setopt(fd, SOL_SOCKET, SO_SNDBUF, val) < 0) {
25410004Sdai.ngo@sun.com syslog(LOG_ERR,
25510004Sdai.ngo@sun.com "couldn't set SO_SNDBUF to %d - t_errno = %d",
25610004Sdai.ngo@sun.com val, t_errno);
25710004Sdai.ngo@sun.com syslog(LOG_ERR,
25810004Sdai.ngo@sun.com "Check and increase system-wide tcp_max_buf");
25910004Sdai.ngo@sun.com }
26010004Sdai.ngo@sun.com }
26110004Sdai.ngo@sun.com
26210004Sdai.ngo@sun.com curval = get_opt(fd, SOL_SOCKET, SO_RCVBUF);
26310004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Current SO_RCVBUF value is %d", curval);
26410004Sdai.ngo@sun.com if ((curval != -1) && (curval < val)) {
26510004Sdai.ngo@sun.com syslog(LOG_DEBUG, "Set SO_RCVBUF option to %d", val);
26610004Sdai.ngo@sun.com if (setopt(fd, SOL_SOCKET, SO_RCVBUF, val) < 0) {
26710004Sdai.ngo@sun.com syslog(LOG_ERR,
26810004Sdai.ngo@sun.com "couldn't set SO_RCVBUF to %d - t_errno = %d",
26910004Sdai.ngo@sun.com val, t_errno);
27010004Sdai.ngo@sun.com syslog(LOG_ERR,
27110004Sdai.ngo@sun.com "Check and increase system-wide tcp_max_buf");
27210004Sdai.ngo@sun.com }
27310004Sdai.ngo@sun.com }
27410004Sdai.ngo@sun.com }
27510004Sdai.ngo@sun.com
2760Sstevel@tonic-gate int
nfslib_bindit(struct netconfig * nconf,struct netbuf ** addr,struct nd_hostserv * hs,int backlog)2770Sstevel@tonic-gate nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
2780Sstevel@tonic-gate struct nd_hostserv *hs, int backlog)
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate int fd;
2810Sstevel@tonic-gate struct t_bind *ntb;
2820Sstevel@tonic-gate struct t_bind tb;
2830Sstevel@tonic-gate struct nd_addrlist *addrlist;
2840Sstevel@tonic-gate struct t_optmgmt req, resp;
2850Sstevel@tonic-gate struct opthdr *opt;
2860Sstevel@tonic-gate char reqbuf[128];
2870Sstevel@tonic-gate bool_t use_any = FALSE;
2881676Sjpk bool_t gzone = TRUE;
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate if ((fd = nfslib_transport_open(nconf)) == -1) {
2910Sstevel@tonic-gate syslog(LOG_ERR, "cannot establish transport service over %s",
2927208Svv149972 nconf->nc_device);
2930Sstevel@tonic-gate return (-1);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate addrlist = (struct nd_addrlist *)NULL;
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate /* nfs4_callback service does not used a fieed port number */
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate if (strcmp(hs->h_serv, "nfs4_callback") == 0) {
3010Sstevel@tonic-gate tb.addr.maxlen = 0;
3020Sstevel@tonic-gate tb.addr.len = 0;
3030Sstevel@tonic-gate tb.addr.buf = 0;
3040Sstevel@tonic-gate use_any = TRUE;
3051676Sjpk gzone = (getzoneid() == GLOBAL_ZONEID);
3060Sstevel@tonic-gate } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate syslog(LOG_ERR,
3090Sstevel@tonic-gate "Cannot get address for transport %s host %s service %s",
3107208Svv149972 nconf->nc_netid, hs->h_host, hs->h_serv);
3110Sstevel@tonic-gate (void) t_close(fd);
3120Sstevel@tonic-gate return (-1);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) {
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate * If we're running over TCP, then set the
3180Sstevel@tonic-gate * SO_REUSEADDR option so that we can bind
3190Sstevel@tonic-gate * to our preferred address even if previously
3200Sstevel@tonic-gate * left connections exist in FIN_WAIT states.
3210Sstevel@tonic-gate * This is somewhat bogus, but otherwise you have
3220Sstevel@tonic-gate * to wait 2 minutes to restart after killing it.
3230Sstevel@tonic-gate */
3240Sstevel@tonic-gate if (reuseaddr(fd) == -1) {
3250Sstevel@tonic-gate syslog(LOG_WARNING,
3260Sstevel@tonic-gate "couldn't set SO_REUSEADDR option on transport");
3270Sstevel@tonic-gate }
3281676Sjpk } else if (strcmp(nconf->nc_proto, "udp") == 0) {
3291676Sjpk /*
3301676Sjpk * In order to run MLP on UDP, we need to handle creds.
3311676Sjpk */
3321676Sjpk if (recvucred(fd) == -1) {
3331676Sjpk syslog(LOG_WARNING,
3341676Sjpk "couldn't set SO_RECVUCRED option on transport");
3351676Sjpk }
3361676Sjpk }
3371676Sjpk
3381676Sjpk /*
3391676Sjpk * Make non global zone nfs4_callback port MLP
3401676Sjpk */
3411676Sjpk if (use_any && is_system_labeled() && !gzone) {
3421676Sjpk if (anonmlp(fd) == -1) {
3431676Sjpk /*
3441676Sjpk * failing to set this option means nfs4_callback
3451676Sjpk * could fail silently later. So fail it with
3461676Sjpk * with an error message now.
3471676Sjpk */
3481676Sjpk syslog(LOG_ERR,
3491676Sjpk "couldn't set SO_ANON_MLP option on transport");
3501676Sjpk (void) t_close(fd);
3511676Sjpk return (-1);
3521676Sjpk }
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_CLTS)
3560Sstevel@tonic-gate tb.qlen = 0;
3570Sstevel@tonic-gate else
3580Sstevel@tonic-gate tb.qlen = backlog;
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate /* LINTED pointer alignment */
3610Sstevel@tonic-gate ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
3620Sstevel@tonic-gate if (ntb == (struct t_bind *)NULL) {
3630Sstevel@tonic-gate syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno);
3640Sstevel@tonic-gate (void) t_close(fd);
3650Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST);
3660Sstevel@tonic-gate return (-1);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate /*
3700Sstevel@tonic-gate * XXX - what about the space tb->addr.buf points to? This should
3710Sstevel@tonic-gate * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,)
3720Sstevel@tonic-gate * should't be called with T_ALL.
3730Sstevel@tonic-gate */
3740Sstevel@tonic-gate if (addrlist)
3750Sstevel@tonic-gate tb.addr = *(addrlist->n_addrs); /* structure copy */
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate if (t_bind(fd, &tb, ntb) == -1) {
3780Sstevel@tonic-gate syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno);
3790Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND);
3800Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST);
3810Sstevel@tonic-gate (void) t_close(fd);
3820Sstevel@tonic-gate return (-1);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /* make sure we bound to the right address */
3860Sstevel@tonic-gate if (use_any == FALSE &&
3870Sstevel@tonic-gate (tb.addr.len != ntb->addr.len ||
3880Sstevel@tonic-gate memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) {
3890Sstevel@tonic-gate syslog(LOG_ERR, "t_bind to wrong address");
3900Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND);
3910Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST);
3920Sstevel@tonic-gate (void) t_close(fd);
3930Sstevel@tonic-gate return (-1);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate /*
3970Sstevel@tonic-gate * Call nfs4svc_setport so that the kernel can be
3980Sstevel@tonic-gate * informed what port number the daemon is listing
3990Sstevel@tonic-gate * for incoming connection requests.
4000Sstevel@tonic-gate */
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS ||
4030Sstevel@tonic-gate nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL)
4040Sstevel@tonic-gate (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr);
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate *addr = &ntb->addr;
4070Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST);
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) {
4100Sstevel@tonic-gate /*
4110Sstevel@tonic-gate * Disable the Nagle algorithm on TCP connections.
4120Sstevel@tonic-gate * Connections accepted from this listener will
4130Sstevel@tonic-gate * inherit the listener options.
4140Sstevel@tonic-gate */
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /* LINTED pointer alignment */
4170Sstevel@tonic-gate opt = (struct opthdr *)reqbuf;
4180Sstevel@tonic-gate opt->level = IPPROTO_TCP;
4190Sstevel@tonic-gate opt->name = TCP_NODELAY;
4200Sstevel@tonic-gate opt->len = sizeof (int);
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate /* LINTED pointer alignment */
4230Sstevel@tonic-gate *(int *)((char *)opt + sizeof (*opt)) = 1;
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate req.flags = T_NEGOTIATE;
4260Sstevel@tonic-gate req.opt.len = sizeof (*opt) + opt->len;
4270Sstevel@tonic-gate req.opt.buf = (char *)opt;
4280Sstevel@tonic-gate resp.flags = 0;
4290Sstevel@tonic-gate resp.opt.buf = reqbuf;
4300Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf);
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 ||
4337208Svv149972 resp.flags != T_SUCCESS) {
4340Sstevel@tonic-gate syslog(LOG_ERR,
4350Sstevel@tonic-gate "couldn't set NODELAY option for proto %s: t_errno = %d, %m",
4367208Svv149972 nconf->nc_proto, t_errno);
4370Sstevel@tonic-gate }
43810004Sdai.ngo@sun.com
43910004Sdai.ngo@sun.com nfslib_set_sockbuf(fd);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate return (fd);
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate static int
get_opt(int fd,int level,int name)44610004Sdai.ngo@sun.com get_opt(int fd, int level, int name)
44710004Sdai.ngo@sun.com {
44810004Sdai.ngo@sun.com struct t_optmgmt req, res;
44910004Sdai.ngo@sun.com struct {
45010004Sdai.ngo@sun.com struct opthdr opt;
45110004Sdai.ngo@sun.com int value;
45210004Sdai.ngo@sun.com } reqbuf;
45310004Sdai.ngo@sun.com
45410004Sdai.ngo@sun.com reqbuf.opt.level = level;
45510004Sdai.ngo@sun.com reqbuf.opt.name = name;
45610004Sdai.ngo@sun.com reqbuf.opt.len = sizeof (int);
45710004Sdai.ngo@sun.com reqbuf.value = 0;
45810004Sdai.ngo@sun.com
45910004Sdai.ngo@sun.com req.flags = T_CURRENT;
46010004Sdai.ngo@sun.com req.opt.len = sizeof (reqbuf);
46110004Sdai.ngo@sun.com req.opt.buf = (char *)&reqbuf;
46210004Sdai.ngo@sun.com
46310004Sdai.ngo@sun.com res.flags = 0;
46410004Sdai.ngo@sun.com res.opt.buf = (char *)&reqbuf;
46510004Sdai.ngo@sun.com res.opt.maxlen = sizeof (reqbuf);
46610004Sdai.ngo@sun.com
46710004Sdai.ngo@sun.com if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) {
46810004Sdai.ngo@sun.com t_error("t_optmgmt");
46910004Sdai.ngo@sun.com return (-1);
47010004Sdai.ngo@sun.com }
47110004Sdai.ngo@sun.com return (reqbuf.value);
47210004Sdai.ngo@sun.com }
47310004Sdai.ngo@sun.com
47410004Sdai.ngo@sun.com static int
setopt(int fd,int level,int name,int value)4751676Sjpk setopt(int fd, int level, int name, int value)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate struct t_optmgmt req, resp;
4781676Sjpk struct {
4791676Sjpk struct opthdr opt;
4801676Sjpk int value;
4811676Sjpk } reqbuf;
4820Sstevel@tonic-gate
4831676Sjpk reqbuf.opt.level = level;
4841676Sjpk reqbuf.opt.name = name;
4851676Sjpk reqbuf.opt.len = sizeof (int);
4860Sstevel@tonic-gate
4871676Sjpk reqbuf.value = value;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate req.flags = T_NEGOTIATE;
4901676Sjpk req.opt.len = sizeof (reqbuf);
4911676Sjpk req.opt.buf = (char *)&reqbuf;
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate resp.flags = 0;
4941676Sjpk resp.opt.buf = (char *)&reqbuf;
4950Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf);
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
4980Sstevel@tonic-gate t_error("t_optmgmt");
4990Sstevel@tonic-gate return (-1);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate return (0);
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate
5041676Sjpk static int
reuseaddr(int fd)5051676Sjpk reuseaddr(int fd)
5061676Sjpk {
5071676Sjpk return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1));
5081676Sjpk }
5091676Sjpk
5101676Sjpk static int
recvucred(int fd)5111676Sjpk recvucred(int fd)
5121676Sjpk {
5131676Sjpk return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1));
5141676Sjpk }
5151676Sjpk
5161676Sjpk static int
anonmlp(int fd)5171676Sjpk anonmlp(int fd)
5181676Sjpk {
5191676Sjpk return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1));
5201676Sjpk }
5211676Sjpk
5220Sstevel@tonic-gate void
nfslib_log_tli_error(char * tli_name,int fd,struct netconfig * nconf)5230Sstevel@tonic-gate nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate int error;
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate * Save the error code across syslog(), just in case syslog()
5290Sstevel@tonic-gate * gets its own error and, therefore, overwrites errno.
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate error = errno;
5320Sstevel@tonic-gate if (t_errno == TSYSERR) {
5330Sstevel@tonic-gate syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
5347208Svv149972 tli_name, fd, nconf->nc_proto);
5350Sstevel@tonic-gate } else {
5360Sstevel@tonic-gate syslog(LOG_ERR,
5377208Svv149972 "%s(file descriptor %d/transport %s) TLI error %d",
5387208Svv149972 tli_name, fd, nconf->nc_proto, t_errno);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate errno = error;
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate * Called to set up service over a particular transport.
5450Sstevel@tonic-gate */
5460Sstevel@tonic-gate void
do_one(char * provider,NETSELDECL (proto),struct protob * protobp0,int (* svc)(int,struct netbuf,struct netconfig *))5470Sstevel@tonic-gate do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
548*12648SSurya.Prakki@Sun.COM int (*svc)(int, struct netbuf, struct netconfig *))
5490Sstevel@tonic-gate {
5500Sstevel@tonic-gate register int sock;
5510Sstevel@tonic-gate struct protob *protobp;
5520Sstevel@tonic-gate struct netbuf *retaddr;
5530Sstevel@tonic-gate struct netconfig *retnconf;
5540Sstevel@tonic-gate struct netbuf addrmask;
5550Sstevel@tonic-gate int vers;
5560Sstevel@tonic-gate int err;
5570Sstevel@tonic-gate int l;
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate if (provider)
5600Sstevel@tonic-gate sock = bind_to_provider(provider, protobp0->serv, &retaddr,
5617208Svv149972 &retnconf);
5620Sstevel@tonic-gate else
5630Sstevel@tonic-gate sock = bind_to_proto(proto, protobp0->serv, &retaddr,
5647208Svv149972 &retnconf);
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate if (sock == -1) {
5670Sstevel@tonic-gate (void) syslog(LOG_ERR,
5680Sstevel@tonic-gate "Cannot establish %s service over %s: transport setup problem.",
5697208Svv149972 protobp0->serv, provider ? provider : proto);
5700Sstevel@tonic-gate return;
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate if (set_addrmask(sock, retnconf, &addrmask) < 0) {
5740Sstevel@tonic-gate (void) syslog(LOG_ERR,
5750Sstevel@tonic-gate "Cannot set address mask for %s", retnconf->nc_netid);
5760Sstevel@tonic-gate return;
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate /*
5800Sstevel@tonic-gate * Register all versions of the programs in the protocol block list.
5810Sstevel@tonic-gate */
5820Sstevel@tonic-gate l = strlen(NC_UDP);
5830Sstevel@tonic-gate for (protobp = protobp0; protobp; protobp = protobp->next) {
5840Sstevel@tonic-gate for (vers = protobp->versmin; vers <= protobp->versmax;
5857208Svv149972 vers++) {
5860Sstevel@tonic-gate if ((protobp->program == NFS_PROGRAM ||
5877208Svv149972 protobp->program == NFS_ACL_PROGRAM) &&
5887208Svv149972 vers == NFS_V4 &&
5897208Svv149972 strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0)
5900Sstevel@tonic-gate continue;
5910Sstevel@tonic-gate
592*12648SSurya.Prakki@Sun.COM (void) rpcb_unset(protobp->program, vers, retnconf);
593*12648SSurya.Prakki@Sun.COM (void) rpcb_set(protobp->program, vers, retnconf,
594*12648SSurya.Prakki@Sun.COM retaddr);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate if (retnconf->nc_semantics == NC_TPI_CLTS) {
5990Sstevel@tonic-gate /* Don't drop core if supporting module(s) aren't loaded. */
6000Sstevel@tonic-gate (void) signal(SIGSYS, SIG_IGN);
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate * svc() doesn't block, it returns success or failure.
6040Sstevel@tonic-gate */
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate if (svc == NULL && Mysvc4 != NULL)
6070Sstevel@tonic-gate err = (*Mysvc4)(sock, &addrmask, retnconf,
6087208Svv149972 NFS4_SETPORT|NFS4_KRPC_START, retaddr);
6090Sstevel@tonic-gate else
6100Sstevel@tonic-gate err = (*svc)(sock, addrmask, retnconf);
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate if (err < 0) {
6130Sstevel@tonic-gate (void) syslog(LOG_ERR,
6147208Svv149972 "Cannot establish %s service over <file desc."
6157208Svv149972 " %d, protocol %s> : %m. Exiting",
6167208Svv149972 protobp0->serv, sock, retnconf->nc_proto);
6170Sstevel@tonic-gate exit(1);
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate /*
6220Sstevel@tonic-gate * We successfully set up the server over this transport.
6230Sstevel@tonic-gate * Add this descriptor to the one being polled on.
6240Sstevel@tonic-gate */
6250Sstevel@tonic-gate add_to_poll_list(sock, retnconf);
6260Sstevel@tonic-gate }
62710004Sdai.ngo@sun.com
6280Sstevel@tonic-gate /*
6290Sstevel@tonic-gate * Set up the NFS service over all the available transports.
6300Sstevel@tonic-gate * Returns -1 for failure, 0 for success.
6310Sstevel@tonic-gate */
6320Sstevel@tonic-gate int
do_all(struct protob * protobp,int (* svc)(int,struct netbuf,struct netconfig *))6330Sstevel@tonic-gate do_all(struct protob *protobp,
634*12648SSurya.Prakki@Sun.COM int (*svc)(int, struct netbuf, struct netconfig *))
6350Sstevel@tonic-gate {
6360Sstevel@tonic-gate struct netconfig *nconf;
6370Sstevel@tonic-gate NCONF_HANDLE *nc;
6380Sstevel@tonic-gate int l;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
6410Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m");
6420Sstevel@tonic-gate return (-1);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate l = strlen(NC_UDP);
6450Sstevel@tonic-gate while (nconf = getnetconfig(nc)) {
6460Sstevel@tonic-gate if ((nconf->nc_flag & NC_VISIBLE) &&
6470Sstevel@tonic-gate strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
6480Sstevel@tonic-gate OK_TPI_TYPE(nconf) &&
6490Sstevel@tonic-gate (protobp->program != NFS4_CALLBACK ||
6500Sstevel@tonic-gate strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
6510Sstevel@tonic-gate do_one(nconf->nc_device, nconf->nc_proto,
652*12648SSurya.Prakki@Sun.COM protobp, svc);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate (void) endnetconfig(nc);
6550Sstevel@tonic-gate return (0);
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate * poll on the open transport descriptors for events and errors.
6600Sstevel@tonic-gate */
6610Sstevel@tonic-gate void
poll_for_action(void)6620Sstevel@tonic-gate poll_for_action(void)
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate int nfds;
6650Sstevel@tonic-gate int i;
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate * Keep polling until all transports have been closed. When this
6690Sstevel@tonic-gate * happens, we return.
6700Sstevel@tonic-gate */
6710Sstevel@tonic-gate while ((int)num_fds > 0) {
6720Sstevel@tonic-gate nfds = poll(poll_array, num_fds, INFTIM);
6730Sstevel@tonic-gate switch (nfds) {
6740Sstevel@tonic-gate case 0:
6750Sstevel@tonic-gate continue;
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate case -1:
6780Sstevel@tonic-gate /*
6790Sstevel@tonic-gate * Some errors from poll could be
6800Sstevel@tonic-gate * due to temporary conditions, and we try to
6810Sstevel@tonic-gate * be robust in the face of them. Other
6820Sstevel@tonic-gate * errors (should never happen in theory)
6830Sstevel@tonic-gate * are fatal (eg. EINVAL, EFAULT).
6840Sstevel@tonic-gate */
6850Sstevel@tonic-gate switch (errno) {
6860Sstevel@tonic-gate case EINTR:
6877208Svv149972 continue;
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate case EAGAIN:
6900Sstevel@tonic-gate case ENOMEM:
6910Sstevel@tonic-gate (void) sleep(10);
6920Sstevel@tonic-gate continue;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate default:
6950Sstevel@tonic-gate (void) syslog(LOG_ERR,
6967208Svv149972 "poll failed: %m. Exiting");
6970Sstevel@tonic-gate exit(1);
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate default:
7000Sstevel@tonic-gate break;
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate /*
7040Sstevel@tonic-gate * Go through the poll list looking for events.
7050Sstevel@tonic-gate */
7060Sstevel@tonic-gate for (i = 0; i < num_fds && nfds > 0; i++) {
7070Sstevel@tonic-gate if (poll_array[i].revents) {
7080Sstevel@tonic-gate nfds--;
7090Sstevel@tonic-gate /*
7100Sstevel@tonic-gate * We have a message, so try to read it.
7110Sstevel@tonic-gate * Record the error return in errno,
7120Sstevel@tonic-gate * so that syslog(LOG_ERR, "...%m")
7130Sstevel@tonic-gate * dumps the corresponding error string.
7140Sstevel@tonic-gate */
7150Sstevel@tonic-gate if (conn_polled[i].nc.nc_semantics ==
7160Sstevel@tonic-gate NC_TPI_CLTS) {
7170Sstevel@tonic-gate errno = do_poll_clts_action(
7187208Svv149972 poll_array[i].fd, i);
7190Sstevel@tonic-gate } else {
7200Sstevel@tonic-gate errno = do_poll_cots_action(
7217208Svv149972 poll_array[i].fd, i);
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate if (errno == 0)
7250Sstevel@tonic-gate continue;
7260Sstevel@tonic-gate /*
7270Sstevel@tonic-gate * Most returned error codes mean that there is
7280Sstevel@tonic-gate * fatal condition which we can only deal with
7290Sstevel@tonic-gate * by closing the transport.
7300Sstevel@tonic-gate */
7310Sstevel@tonic-gate if (errno != EAGAIN && errno != ENOMEM) {
7320Sstevel@tonic-gate (void) syslog(LOG_ERR,
7330Sstevel@tonic-gate "Error (%m) reading descriptor %d/transport %s. Closing it.",
7347208Svv149972 poll_array[i].fd,
7357208Svv149972 conn_polled[i].nc.nc_proto);
7360Sstevel@tonic-gate (void) t_close(poll_array[i].fd);
7370Sstevel@tonic-gate remove_from_poll_list(poll_array[i].fd);
7380Sstevel@tonic-gate
7390Sstevel@tonic-gate } else if (errno == ENOMEM)
7400Sstevel@tonic-gate (void) sleep(5);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate (void) syslog(LOG_ERR,
7467208Svv149972 "All transports have been closed with errors. Exiting.");
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate /*
7500Sstevel@tonic-gate * Allocate poll/transport array entries for this descriptor.
7510Sstevel@tonic-gate */
7520Sstevel@tonic-gate static void
add_to_poll_list(int fd,struct netconfig * nconf)7530Sstevel@tonic-gate add_to_poll_list(int fd, struct netconfig *nconf)
7540Sstevel@tonic-gate {
7550Sstevel@tonic-gate static int poll_array_size = 0;
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate /*
7580Sstevel@tonic-gate * If the arrays are full, allocate new ones.
7590Sstevel@tonic-gate */
7600Sstevel@tonic-gate if (num_fds == poll_array_size) {
7610Sstevel@tonic-gate struct pollfd *tpa;
7620Sstevel@tonic-gate struct conn_entry *tnp;
7630Sstevel@tonic-gate
7640Sstevel@tonic-gate if (poll_array_size != 0) {
7650Sstevel@tonic-gate tpa = poll_array;
7660Sstevel@tonic-gate tnp = conn_polled;
7670Sstevel@tonic-gate } else
7680Sstevel@tonic-gate tpa = (struct pollfd *)0;
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate poll_array_size += POLL_ARRAY_INC_SIZE;
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate * Allocate new arrays.
7730Sstevel@tonic-gate */
7740Sstevel@tonic-gate poll_array = (struct pollfd *)
7750Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct pollfd) + 256);
7760Sstevel@tonic-gate conn_polled = (struct conn_entry *)
7770Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct conn_entry) + 256);
7780Sstevel@tonic-gate if (poll_array == (struct pollfd *)NULL ||
7790Sstevel@tonic-gate conn_polled == (struct conn_entry *)NULL) {
7800Sstevel@tonic-gate syslog(LOG_ERR, "malloc failed for poll array");
7810Sstevel@tonic-gate exit(1);
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate /*
7850Sstevel@tonic-gate * Copy the data of the old ones into new arrays, and
7860Sstevel@tonic-gate * free the old ones.
7870Sstevel@tonic-gate */
7880Sstevel@tonic-gate if (tpa) {
7890Sstevel@tonic-gate (void) memcpy((void *)poll_array, (void *)tpa,
7907208Svv149972 num_fds * sizeof (struct pollfd));
7910Sstevel@tonic-gate (void) memcpy((void *)conn_polled, (void *)tnp,
7927208Svv149972 num_fds * sizeof (struct conn_entry));
7930Sstevel@tonic-gate free((void *)tpa);
7940Sstevel@tonic-gate free((void *)tnp);
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate /*
7990Sstevel@tonic-gate * Set the descriptor and event list. All possible events are
8000Sstevel@tonic-gate * polled for.
8010Sstevel@tonic-gate */
8020Sstevel@tonic-gate poll_array[num_fds].fd = fd;
8030Sstevel@tonic-gate poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate /*
8060Sstevel@tonic-gate * Copy the transport data over too.
8070Sstevel@tonic-gate */
8080Sstevel@tonic-gate conn_polled[num_fds].nc = *nconf;
8090Sstevel@tonic-gate conn_polled[num_fds].closing = 0;
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate /*
8120Sstevel@tonic-gate * Set the descriptor to non-blocking. Avoids a race
8130Sstevel@tonic-gate * between data arriving on the stream and then having it
8140Sstevel@tonic-gate * flushed before we can read it.
8150Sstevel@tonic-gate */
8160Sstevel@tonic-gate if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
8170Sstevel@tonic-gate (void) syslog(LOG_ERR,
8180Sstevel@tonic-gate "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting",
8197208Svv149972 num_fds, nconf->nc_proto);
8200Sstevel@tonic-gate exit(1);
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate
8230Sstevel@tonic-gate /*
8240Sstevel@tonic-gate * Count this descriptor.
8250Sstevel@tonic-gate */
8260Sstevel@tonic-gate ++num_fds;
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate static void
remove_from_poll_list(int fd)8300Sstevel@tonic-gate remove_from_poll_list(int fd)
8310Sstevel@tonic-gate {
8320Sstevel@tonic-gate int i;
8330Sstevel@tonic-gate int num_to_copy;
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate for (i = 0; i < num_fds; i++) {
8360Sstevel@tonic-gate if (poll_array[i].fd == fd) {
8370Sstevel@tonic-gate --num_fds;
8380Sstevel@tonic-gate num_to_copy = num_fds - i;
8390Sstevel@tonic-gate (void) memcpy((void *)&poll_array[i],
8407208Svv149972 (void *)&poll_array[i+1],
8417208Svv149972 num_to_copy * sizeof (struct pollfd));
8420Sstevel@tonic-gate (void) memset((void *)&poll_array[num_fds], 0,
8437208Svv149972 sizeof (struct pollfd));
8440Sstevel@tonic-gate (void) memcpy((void *)&conn_polled[i],
8457208Svv149972 (void *)&conn_polled[i+1],
8467208Svv149972 num_to_copy * sizeof (struct conn_entry));
8470Sstevel@tonic-gate (void) memset((void *)&conn_polled[num_fds], 0,
8487208Svv149972 sizeof (struct conn_entry));
8490Sstevel@tonic-gate return;
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate }
8520Sstevel@tonic-gate syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate
8560Sstevel@tonic-gate /*
8570Sstevel@tonic-gate * Called to read and interpret the event on a connectionless descriptor.
8580Sstevel@tonic-gate * Returns 0 if successful, or a UNIX error code if failure.
8590Sstevel@tonic-gate */
8600Sstevel@tonic-gate static int
do_poll_clts_action(int fd,int conn_index)8610Sstevel@tonic-gate do_poll_clts_action(int fd, int conn_index)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate int error;
8640Sstevel@tonic-gate int ret;
8650Sstevel@tonic-gate int flags;
8660Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc;
8670Sstevel@tonic-gate static struct t_unitdata *unitdata = NULL;
8680Sstevel@tonic-gate static struct t_uderr *uderr = NULL;
8690Sstevel@tonic-gate static int oldfd = -1;
8700Sstevel@tonic-gate struct nd_hostservlist *host = NULL;
8710Sstevel@tonic-gate struct strbuf ctl[1], data[1];
8720Sstevel@tonic-gate /*
8730Sstevel@tonic-gate * We just need to have some space to consume the
8740Sstevel@tonic-gate * message in the event we can't use the TLI interface to do the
8750Sstevel@tonic-gate * job.
8760Sstevel@tonic-gate *
8770Sstevel@tonic-gate * We flush the message using getmsg(). For the control part
8780Sstevel@tonic-gate * we allocate enough for any TPI header plus 32 bytes for address
8790Sstevel@tonic-gate * and options. For the data part, there is nothing magic about
8800Sstevel@tonic-gate * the size of the array, but 256 bytes is probably better than
8810Sstevel@tonic-gate * 1 byte, and we don't expect any data portion anyway.
8820Sstevel@tonic-gate *
8830Sstevel@tonic-gate * If the array sizes are too small, we handle this because getmsg()
8840Sstevel@tonic-gate * (called to consume the message) will return MOREDATA|MORECTL.
8850Sstevel@tonic-gate * Thus we just call getmsg() until it's read the message.
8860Sstevel@tonic-gate */
8870Sstevel@tonic-gate char ctlbuf[sizeof (union T_primitives) + 32];
8880Sstevel@tonic-gate char databuf[256];
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate /*
8910Sstevel@tonic-gate * If this is the same descriptor as the last time
8920Sstevel@tonic-gate * do_poll_clts_action was called, we can save some
8930Sstevel@tonic-gate * de-allocation and allocation.
8940Sstevel@tonic-gate */
8950Sstevel@tonic-gate if (oldfd != fd) {
8960Sstevel@tonic-gate oldfd = fd;
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate if (unitdata) {
8990Sstevel@tonic-gate (void) t_free((char *)unitdata, T_UNITDATA);
9000Sstevel@tonic-gate unitdata = NULL;
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate if (uderr) {
9030Sstevel@tonic-gate (void) t_free((char *)uderr, T_UDERROR);
9040Sstevel@tonic-gate uderr = NULL;
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate /*
9090Sstevel@tonic-gate * Allocate a unitdata structure for receiving the event.
9100Sstevel@tonic-gate */
9110Sstevel@tonic-gate if (unitdata == NULL) {
9120Sstevel@tonic-gate /* LINTED pointer alignment */
9130Sstevel@tonic-gate unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
9140Sstevel@tonic-gate if (unitdata == NULL) {
9150Sstevel@tonic-gate if (t_errno == TSYSERR) {
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate * Save the error code across
9180Sstevel@tonic-gate * syslog(), just in case
9190Sstevel@tonic-gate * syslog() gets its own error
9200Sstevel@tonic-gate * and therefore overwrites errno.
9210Sstevel@tonic-gate */
9220Sstevel@tonic-gate error = errno;
9230Sstevel@tonic-gate (void) syslog(LOG_ERR,
9240Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
9257208Svv149972 fd, nconf->nc_proto);
9260Sstevel@tonic-gate return (error);
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate (void) syslog(LOG_ERR,
9290Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
9307208Svv149972 fd, nconf->nc_proto, t_errno);
9310Sstevel@tonic-gate goto flush_it;
9320Sstevel@tonic-gate }
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate try_again:
9360Sstevel@tonic-gate flags = 0;
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate /*
9390Sstevel@tonic-gate * The idea is we wait for T_UNITDATA_IND's. Of course,
9400Sstevel@tonic-gate * we don't get any, because rpcmod filters them out.
9410Sstevel@tonic-gate * However, we need to call t_rcvudata() to let TLI
9420Sstevel@tonic-gate * tell us we have a T_UDERROR_IND.
9430Sstevel@tonic-gate *
9440Sstevel@tonic-gate * algorithm is:
9450Sstevel@tonic-gate * t_rcvudata(), expecting TLOOK.
9460Sstevel@tonic-gate * t_look(), expecting T_UDERR.
9470Sstevel@tonic-gate * t_rcvuderr(), expecting success (0).
9480Sstevel@tonic-gate * expand destination address into ASCII,
9490Sstevel@tonic-gate * and dump it.
9500Sstevel@tonic-gate */
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate ret = t_rcvudata(fd, unitdata, &flags);
9530Sstevel@tonic-gate if (ret == 0 || t_errno == TBUFOVFLW) {
9540Sstevel@tonic-gate (void) syslog(LOG_WARNING,
9550Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
9567208Svv149972 fd, nconf->nc_proto, unitdata->udata.len);
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate /*
9590Sstevel@tonic-gate * Even though we don't expect any data, in case we do,
9600Sstevel@tonic-gate * keep reading until there is no more.
9610Sstevel@tonic-gate */
9620Sstevel@tonic-gate if (flags & T_MORE)
9630Sstevel@tonic-gate goto try_again;
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate return (0);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate switch (t_errno) {
9690Sstevel@tonic-gate case TNODATA:
9700Sstevel@tonic-gate return (0);
9710Sstevel@tonic-gate case TSYSERR:
9720Sstevel@tonic-gate /*
9730Sstevel@tonic-gate * System errors are returned to caller.
9740Sstevel@tonic-gate * Save the error code across
9750Sstevel@tonic-gate * syslog(), just in case
9760Sstevel@tonic-gate * syslog() gets its own error
9770Sstevel@tonic-gate * and therefore overwrites errno.
9780Sstevel@tonic-gate */
9790Sstevel@tonic-gate error = errno;
9800Sstevel@tonic-gate (void) syslog(LOG_ERR,
9817208Svv149972 "t_rcvudata(file descriptor %d/transport %s) %m",
9827208Svv149972 fd, nconf->nc_proto);
9830Sstevel@tonic-gate return (error);
9840Sstevel@tonic-gate case TLOOK:
9850Sstevel@tonic-gate break;
9860Sstevel@tonic-gate default:
9870Sstevel@tonic-gate (void) syslog(LOG_ERR,
9880Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) TLI error %d",
9897208Svv149972 fd, nconf->nc_proto, t_errno);
9900Sstevel@tonic-gate goto flush_it;
9910Sstevel@tonic-gate }
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate ret = t_look(fd);
9940Sstevel@tonic-gate switch (ret) {
9950Sstevel@tonic-gate case 0:
9960Sstevel@tonic-gate return (0);
9970Sstevel@tonic-gate case -1:
9980Sstevel@tonic-gate /*
9990Sstevel@tonic-gate * System errors are returned to caller.
10000Sstevel@tonic-gate */
10010Sstevel@tonic-gate if (t_errno == TSYSERR) {
10020Sstevel@tonic-gate /*
10030Sstevel@tonic-gate * Save the error code across
10040Sstevel@tonic-gate * syslog(), just in case
10050Sstevel@tonic-gate * syslog() gets its own error
10060Sstevel@tonic-gate * and therefore overwrites errno.
10070Sstevel@tonic-gate */
10080Sstevel@tonic-gate error = errno;
10090Sstevel@tonic-gate (void) syslog(LOG_ERR,
10107208Svv149972 "t_look(file descriptor %d/transport %s) %m",
10117208Svv149972 fd, nconf->nc_proto);
10120Sstevel@tonic-gate return (error);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate (void) syslog(LOG_ERR,
10157208Svv149972 "t_look(file descriptor %d/transport %s) TLI error %d",
10167208Svv149972 fd, nconf->nc_proto, t_errno);
10170Sstevel@tonic-gate goto flush_it;
10180Sstevel@tonic-gate case T_UDERR:
10190Sstevel@tonic-gate break;
10200Sstevel@tonic-gate default:
10210Sstevel@tonic-gate (void) syslog(LOG_WARNING,
10220Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
10237208Svv149972 fd, nconf->nc_proto, ret, T_UDERR);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate if (uderr == NULL) {
10270Sstevel@tonic-gate /* LINTED pointer alignment */
10280Sstevel@tonic-gate uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
10290Sstevel@tonic-gate if (uderr == NULL) {
10300Sstevel@tonic-gate if (t_errno == TSYSERR) {
10310Sstevel@tonic-gate /*
10320Sstevel@tonic-gate * Save the error code across
10330Sstevel@tonic-gate * syslog(), just in case
10340Sstevel@tonic-gate * syslog() gets its own error
10350Sstevel@tonic-gate * and therefore overwrites errno.
10360Sstevel@tonic-gate */
10370Sstevel@tonic-gate error = errno;
10380Sstevel@tonic-gate (void) syslog(LOG_ERR,
10390Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
10407208Svv149972 fd, nconf->nc_proto);
10410Sstevel@tonic-gate return (error);
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate (void) syslog(LOG_ERR,
10440Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
10457208Svv149972 fd, nconf->nc_proto, t_errno);
10460Sstevel@tonic-gate goto flush_it;
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate ret = t_rcvuderr(fd, uderr);
10510Sstevel@tonic-gate if (ret == 0) {
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate * Save the datagram error in errno, so that the
10550Sstevel@tonic-gate * %m argument to syslog picks up the error string.
10560Sstevel@tonic-gate */
10570Sstevel@tonic-gate errno = uderr->error;
10580Sstevel@tonic-gate
10590Sstevel@tonic-gate /*
10600Sstevel@tonic-gate * Log the datagram error, then log the host that
10610Sstevel@tonic-gate * probably triggerred. Cannot log both in the
10620Sstevel@tonic-gate * same transaction because of packet size limitations
10630Sstevel@tonic-gate * in /dev/log.
10640Sstevel@tonic-gate */
10650Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
10660Sstevel@tonic-gate "NFS response over <file descriptor %d/transport %s> generated error: %m",
10677208Svv149972 fd, nconf->nc_proto);
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate /*
10700Sstevel@tonic-gate * Try to map the client's address back to a
10710Sstevel@tonic-gate * name.
10720Sstevel@tonic-gate */
10730Sstevel@tonic-gate ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
10740Sstevel@tonic-gate if (ret != -1 && host && host->h_cnt > 0 &&
10750Sstevel@tonic-gate host->h_hostservs) {
10760Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
10770Sstevel@tonic-gate "Bad NFS response was sent to client with host name: %s; service port: %s",
10787208Svv149972 host->h_hostservs->h_host,
10797208Svv149972 host->h_hostservs->h_serv);
10800Sstevel@tonic-gate } else {
10810Sstevel@tonic-gate int i, j;
10820Sstevel@tonic-gate char *buf;
10830Sstevel@tonic-gate char *hex = "0123456789abcdef";
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * Mapping failed, print the whole thing
10870Sstevel@tonic-gate * in ASCII hex.
10880Sstevel@tonic-gate */
10890Sstevel@tonic-gate buf = (char *)malloc(uderr->addr.len * 2 + 1);
10900Sstevel@tonic-gate for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
10910Sstevel@tonic-gate buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
10920Sstevel@tonic-gate buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate buf[j] = '\0';
10950Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
10960Sstevel@tonic-gate "Bad NFS response was sent to client with transport address: 0x%s",
10977208Svv149972 buf);
10980Sstevel@tonic-gate free((void *)buf);
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate
11010Sstevel@tonic-gate if (ret == 0 && host != NULL)
11020Sstevel@tonic-gate netdir_free((void *)host, ND_HOSTSERVLIST);
11030Sstevel@tonic-gate return (0);
11040Sstevel@tonic-gate }
11050Sstevel@tonic-gate
11060Sstevel@tonic-gate switch (t_errno) {
11070Sstevel@tonic-gate case TNOUDERR:
11080Sstevel@tonic-gate goto flush_it;
11090Sstevel@tonic-gate case TSYSERR:
11100Sstevel@tonic-gate /*
11110Sstevel@tonic-gate * System errors are returned to caller.
11120Sstevel@tonic-gate * Save the error code across
11130Sstevel@tonic-gate * syslog(), just in case
11140Sstevel@tonic-gate * syslog() gets its own error
11150Sstevel@tonic-gate * and therefore overwrites errno.
11160Sstevel@tonic-gate */
11170Sstevel@tonic-gate error = errno;
11180Sstevel@tonic-gate (void) syslog(LOG_ERR,
11197208Svv149972 "t_rcvuderr(file descriptor %d/transport %s) %m",
11207208Svv149972 fd, nconf->nc_proto);
11210Sstevel@tonic-gate return (error);
11220Sstevel@tonic-gate default:
11230Sstevel@tonic-gate (void) syslog(LOG_ERR,
11240Sstevel@tonic-gate "t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
11257208Svv149972 fd, nconf->nc_proto, t_errno);
11260Sstevel@tonic-gate goto flush_it;
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate flush_it:
11300Sstevel@tonic-gate /*
11310Sstevel@tonic-gate * If we get here, then we could not cope with whatever message
11320Sstevel@tonic-gate * we attempted to read, so flush it. If we did read a message,
11330Sstevel@tonic-gate * and one isn't present, that is all right, because fd is in
11340Sstevel@tonic-gate * nonblocking mode.
11350Sstevel@tonic-gate */
11360Sstevel@tonic-gate (void) syslog(LOG_ERR,
11370Sstevel@tonic-gate "Flushing one input message from <file descriptor %d/transport %s>",
11387208Svv149972 fd, nconf->nc_proto);
11390Sstevel@tonic-gate
11400Sstevel@tonic-gate /*
11410Sstevel@tonic-gate * Read and discard the message. Do this this until there is
11420Sstevel@tonic-gate * no more control/data in the message or until we get an error.
11430Sstevel@tonic-gate */
11440Sstevel@tonic-gate do {
11450Sstevel@tonic-gate ctl->maxlen = sizeof (ctlbuf);
11460Sstevel@tonic-gate ctl->buf = ctlbuf;
11470Sstevel@tonic-gate data->maxlen = sizeof (databuf);
11480Sstevel@tonic-gate data->buf = databuf;
11490Sstevel@tonic-gate flags = 0;
11500Sstevel@tonic-gate ret = getmsg(fd, ctl, data, &flags);
11510Sstevel@tonic-gate if (ret == -1)
11520Sstevel@tonic-gate return (errno);
11530Sstevel@tonic-gate } while (ret != 0);
11540Sstevel@tonic-gate
11550Sstevel@tonic-gate return (0);
11560Sstevel@tonic-gate }
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate static void
conn_close_oldest(void)11590Sstevel@tonic-gate conn_close_oldest(void)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate int fd;
11620Sstevel@tonic-gate int i1;
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * Find the oldest connection that is not already in the
11660Sstevel@tonic-gate * process of shutting down.
11670Sstevel@tonic-gate */
11680Sstevel@tonic-gate for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
11690Sstevel@tonic-gate if (i1 >= num_fds)
11700Sstevel@tonic-gate return;
11710Sstevel@tonic-gate if (conn_polled[i1].closing == 0)
11720Sstevel@tonic-gate break;
11730Sstevel@tonic-gate }
11740Sstevel@tonic-gate #ifdef DEBUG
11750Sstevel@tonic-gate printf("too many connections (%d), releasing oldest (%d)\n",
11767208Svv149972 num_conns, poll_array[i1].fd);
11770Sstevel@tonic-gate #else
11780Sstevel@tonic-gate syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
11797208Svv149972 num_conns, poll_array[i1].fd);
11800Sstevel@tonic-gate #endif
11810Sstevel@tonic-gate fd = poll_array[i1].fd;
11820Sstevel@tonic-gate if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
11830Sstevel@tonic-gate /*
11840Sstevel@tonic-gate * For politeness, send a T_DISCON_REQ to the transport
11850Sstevel@tonic-gate * provider. We close the stream anyway.
11860Sstevel@tonic-gate */
11870Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0);
11880Sstevel@tonic-gate num_conns--;
11890Sstevel@tonic-gate remove_from_poll_list(fd);
11900Sstevel@tonic-gate (void) t_close(fd);
11910Sstevel@tonic-gate } else {
11920Sstevel@tonic-gate /*
11930Sstevel@tonic-gate * For orderly release, we do not close the stream
11940Sstevel@tonic-gate * until the T_ORDREL_IND arrives to complete
11950Sstevel@tonic-gate * the handshake.
11960Sstevel@tonic-gate */
11970Sstevel@tonic-gate if (t_sndrel(fd) == 0)
11980Sstevel@tonic-gate conn_polled[i1].closing = 1;
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate static boolean_t
conn_get(int fd,struct netconfig * nconf,struct conn_ind ** connp)12030Sstevel@tonic-gate conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
12040Sstevel@tonic-gate {
12050Sstevel@tonic-gate struct conn_ind *conn;
12060Sstevel@tonic-gate struct conn_ind *next_conn;
12070Sstevel@tonic-gate
12080Sstevel@tonic-gate conn = (struct conn_ind *)malloc(sizeof (*conn));
12090Sstevel@tonic-gate if (conn == NULL) {
12100Sstevel@tonic-gate syslog(LOG_ERR, "malloc for listen indication failed");
12110Sstevel@tonic-gate return (FALSE);
12120Sstevel@tonic-gate }
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate /* LINTED pointer alignment */
12150Sstevel@tonic-gate conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
12160Sstevel@tonic-gate if (conn->conn_call == NULL) {
12170Sstevel@tonic-gate free((char *)conn);
12180Sstevel@tonic-gate nfslib_log_tli_error("t_alloc", fd, nconf);
12190Sstevel@tonic-gate return (FALSE);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate if (t_listen(fd, conn->conn_call) == -1) {
12230Sstevel@tonic-gate nfslib_log_tli_error("t_listen", fd, nconf);
12240Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL);
12250Sstevel@tonic-gate free((char *)conn);
12260Sstevel@tonic-gate return (FALSE);
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate if (conn->conn_call->udata.len > 0) {
12300Sstevel@tonic-gate syslog(LOG_WARNING,
12310Sstevel@tonic-gate "rejecting inbound connection(%s) with %d bytes of connect data",
12327208Svv149972 nconf->nc_proto, conn->conn_call->udata.len);
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate conn->conn_call->udata.len = 0;
12350Sstevel@tonic-gate (void) t_snddis(fd, conn->conn_call);
12360Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL);
12370Sstevel@tonic-gate free((char *)conn);
12380Sstevel@tonic-gate return (FALSE);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate if ((next_conn = *connp) != NULL) {
12420Sstevel@tonic-gate next_conn->conn_prev->conn_next = conn;
12430Sstevel@tonic-gate conn->conn_next = next_conn;
12440Sstevel@tonic-gate conn->conn_prev = next_conn->conn_prev;
12450Sstevel@tonic-gate next_conn->conn_prev = conn;
12460Sstevel@tonic-gate } else {
12470Sstevel@tonic-gate conn->conn_next = conn;
12480Sstevel@tonic-gate conn->conn_prev = conn;
12490Sstevel@tonic-gate *connp = conn;
12500Sstevel@tonic-gate }
12510Sstevel@tonic-gate return (TRUE);
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate static int
discon_get(int fd,struct netconfig * nconf,struct conn_ind ** connp)12550Sstevel@tonic-gate discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
12560Sstevel@tonic-gate {
12570Sstevel@tonic-gate struct conn_ind *conn;
12580Sstevel@tonic-gate struct t_discon discon;
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate discon.udata.buf = (char *)0;
12610Sstevel@tonic-gate discon.udata.maxlen = 0;
12620Sstevel@tonic-gate if (t_rcvdis(fd, &discon) == -1) {
12630Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf);
12640Sstevel@tonic-gate return (-1);
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate conn = *connp;
12680Sstevel@tonic-gate if (conn == NULL)
12690Sstevel@tonic-gate return (0);
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate do {
12720Sstevel@tonic-gate if (conn->conn_call->sequence == discon.sequence) {
12730Sstevel@tonic-gate if (conn->conn_next == conn)
12740Sstevel@tonic-gate *connp = (struct conn_ind *)0;
12750Sstevel@tonic-gate else {
12760Sstevel@tonic-gate if (conn == *connp) {
12770Sstevel@tonic-gate *connp = conn->conn_next;
12780Sstevel@tonic-gate }
12790Sstevel@tonic-gate conn->conn_next->conn_prev = conn->conn_prev;
12800Sstevel@tonic-gate conn->conn_prev->conn_next = conn->conn_next;
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate free((char *)conn);
12830Sstevel@tonic-gate break;
12840Sstevel@tonic-gate }
12850Sstevel@tonic-gate conn = conn->conn_next;
12860Sstevel@tonic-gate } while (conn != *connp);
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate return (0);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate static void
cots_listen_event(int fd,int conn_index)12920Sstevel@tonic-gate cots_listen_event(int fd, int conn_index)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate struct t_call *call;
12950Sstevel@tonic-gate struct conn_ind *conn;
12960Sstevel@tonic-gate struct conn_ind *conn_head;
12970Sstevel@tonic-gate int event;
12980Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc;
12990Sstevel@tonic-gate int new_fd;
13000Sstevel@tonic-gate struct netbuf addrmask;
13010Sstevel@tonic-gate int ret = 0;
13020Sstevel@tonic-gate char *clnt;
13030Sstevel@tonic-gate char *clnt_uaddr = NULL;
13040Sstevel@tonic-gate struct nd_hostservlist *clnt_serv = NULL;
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate conn_head = (struct conn_ind *)0;
13070Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head);
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate while ((conn = conn_head) != NULL) {
13100Sstevel@tonic-gate conn_head = conn->conn_next;
13110Sstevel@tonic-gate if (conn_head == conn)
13120Sstevel@tonic-gate conn_head = (struct conn_ind *)0;
13130Sstevel@tonic-gate else {
13140Sstevel@tonic-gate conn_head->conn_prev = conn->conn_prev;
13150Sstevel@tonic-gate conn->conn_prev->conn_next = conn_head;
13160Sstevel@tonic-gate }
13170Sstevel@tonic-gate call = conn->conn_call;
13180Sstevel@tonic-gate free((char *)conn);
13190Sstevel@tonic-gate
13200Sstevel@tonic-gate /*
13210Sstevel@tonic-gate * If we have already accepted the maximum number of
13220Sstevel@tonic-gate * connections allowed on the command line, then drop
13230Sstevel@tonic-gate * the oldest connection (for any protocol) before
13240Sstevel@tonic-gate * accepting the new connection. Unless explicitly
13250Sstevel@tonic-gate * set on the command line, max_conns_allowed is -1.
13260Sstevel@tonic-gate */
13270Sstevel@tonic-gate if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
13280Sstevel@tonic-gate conn_close_oldest();
13290Sstevel@tonic-gate
13300Sstevel@tonic-gate /*
13310Sstevel@tonic-gate * Create a new transport endpoint for the same proto as
13320Sstevel@tonic-gate * the listener.
13330Sstevel@tonic-gate */
13340Sstevel@tonic-gate new_fd = nfslib_transport_open(nconf);
13350Sstevel@tonic-gate if (new_fd == -1) {
13360Sstevel@tonic-gate call->udata.len = 0;
13370Sstevel@tonic-gate (void) t_snddis(fd, call);
13380Sstevel@tonic-gate (void) t_free((char *)call, T_CALL);
13390Sstevel@tonic-gate syslog(LOG_ERR, "Cannot establish transport over %s",
13407208Svv149972 nconf->nc_device);
13410Sstevel@tonic-gate continue;
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate /* Bind to a generic address/port for the accepting stream. */
13450Sstevel@tonic-gate if (t_bind(new_fd, (struct t_bind *)NULL,
13460Sstevel@tonic-gate (struct t_bind *)NULL) == -1) {
13470Sstevel@tonic-gate nfslib_log_tli_error("t_bind", new_fd, nconf);
13480Sstevel@tonic-gate call->udata.len = 0;
13490Sstevel@tonic-gate (void) t_snddis(fd, call);
13500Sstevel@tonic-gate (void) t_free((char *)call, T_CALL);
13510Sstevel@tonic-gate (void) t_close(new_fd);
13520Sstevel@tonic-gate continue;
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate while (t_accept(fd, new_fd, call) == -1) {
13560Sstevel@tonic-gate if (t_errno != TLOOK) {
13570Sstevel@tonic-gate #ifdef DEBUG
13580Sstevel@tonic-gate nfslib_log_tli_error("t_accept", fd, nconf);
13590Sstevel@tonic-gate #endif
13600Sstevel@tonic-gate call->udata.len = 0;
13610Sstevel@tonic-gate (void) t_snddis(fd, call);
13620Sstevel@tonic-gate (void) t_free((char *)call, T_CALL);
13630Sstevel@tonic-gate (void) t_close(new_fd);
13640Sstevel@tonic-gate goto do_next_conn;
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate while (event = t_look(fd)) {
13670Sstevel@tonic-gate switch (event) {
13680Sstevel@tonic-gate case T_LISTEN:
13690Sstevel@tonic-gate #ifdef DEBUG
13700Sstevel@tonic-gate printf(
13710Sstevel@tonic-gate "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
13720Sstevel@tonic-gate #endif
13730Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head);
13740Sstevel@tonic-gate continue;
13750Sstevel@tonic-gate case T_DISCONNECT:
13760Sstevel@tonic-gate #ifdef DEBUG
13770Sstevel@tonic-gate printf(
13780Sstevel@tonic-gate "cots_listen_event(%s): T_DISCONNECT during accept processing\n",
13797208Svv149972 nconf->nc_proto);
13800Sstevel@tonic-gate #endif
13810Sstevel@tonic-gate (void) discon_get(fd, nconf,
13827208Svv149972 &conn_head);
13830Sstevel@tonic-gate continue;
13840Sstevel@tonic-gate default:
13850Sstevel@tonic-gate syslog(LOG_ERR,
13860Sstevel@tonic-gate "unexpected event 0x%x during accept processing (%s)",
13877208Svv149972 event, nconf->nc_proto);
13880Sstevel@tonic-gate call->udata.len = 0;
13890Sstevel@tonic-gate (void) t_snddis(fd, call);
13900Sstevel@tonic-gate (void) t_free((char *)call, T_CALL);
13910Sstevel@tonic-gate (void) t_close(new_fd);
13920Sstevel@tonic-gate goto do_next_conn;
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate }
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
13980Sstevel@tonic-gate (void) syslog(LOG_ERR,
13990Sstevel@tonic-gate "Cannot set address mask for %s",
14007208Svv149972 nconf->nc_netid);
14010Sstevel@tonic-gate return;
14020Sstevel@tonic-gate }
14030Sstevel@tonic-gate
14040Sstevel@tonic-gate /* Tell KRPC about the new stream. */
14050Sstevel@tonic-gate if (Mysvc4 != NULL)
14060Sstevel@tonic-gate ret = (*Mysvc4)(new_fd, &addrmask, nconf,
14077208Svv149972 NFS4_KRPC_START, &call->addr);
14080Sstevel@tonic-gate else
14090Sstevel@tonic-gate ret = (*Mysvc)(new_fd, addrmask, nconf);
14100Sstevel@tonic-gate
14110Sstevel@tonic-gate if (ret < 0) {
14120Sstevel@tonic-gate if (errno != ENOTCONN) {
14130Sstevel@tonic-gate syslog(LOG_ERR,
14140Sstevel@tonic-gate "unable to register new connection: %m");
14150Sstevel@tonic-gate } else {
14160Sstevel@tonic-gate /*
14170Sstevel@tonic-gate * This is the only error that could be
14180Sstevel@tonic-gate * caused by the client, so who was it?
14190Sstevel@tonic-gate */
14200Sstevel@tonic-gate if (netdir_getbyaddr(nconf, &clnt_serv,
14210Sstevel@tonic-gate &(call->addr)) == ND_OK &&
14220Sstevel@tonic-gate clnt_serv->h_cnt > 0)
14230Sstevel@tonic-gate clnt = clnt_serv->h_hostservs->h_host;
14240Sstevel@tonic-gate else
14250Sstevel@tonic-gate clnt = clnt_uaddr = taddr2uaddr(nconf,
14260Sstevel@tonic-gate &(call->addr));
14270Sstevel@tonic-gate /*
14280Sstevel@tonic-gate * If we don't know who the client was,
14290Sstevel@tonic-gate * remain silent.
14300Sstevel@tonic-gate */
14310Sstevel@tonic-gate if (clnt)
14320Sstevel@tonic-gate syslog(LOG_ERR,
14330Sstevel@tonic-gate "unable to register new connection: client %s has dropped connection", clnt);
14340Sstevel@tonic-gate if (clnt_serv)
14350Sstevel@tonic-gate netdir_free(clnt_serv, ND_HOSTSERVLIST);
14360Sstevel@tonic-gate if (clnt_uaddr)
14370Sstevel@tonic-gate free(clnt_uaddr);
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate free(addrmask.buf);
14400Sstevel@tonic-gate (void) t_snddis(new_fd, (struct t_call *)0);
14410Sstevel@tonic-gate (void) t_free((char *)call, T_CALL);
14420Sstevel@tonic-gate (void) t_close(new_fd);
14430Sstevel@tonic-gate goto do_next_conn;
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate
14460Sstevel@tonic-gate free(addrmask.buf);
14470Sstevel@tonic-gate (void) t_free((char *)call, T_CALL);
14480Sstevel@tonic-gate
14490Sstevel@tonic-gate /*
14500Sstevel@tonic-gate * Poll on the new descriptor so that we get disconnect
14510Sstevel@tonic-gate * and orderly release indications.
14520Sstevel@tonic-gate */
14530Sstevel@tonic-gate num_conns++;
14540Sstevel@tonic-gate add_to_poll_list(new_fd, nconf);
14550Sstevel@tonic-gate
14560Sstevel@tonic-gate /* Reset nconf in case it has been moved. */
14570Sstevel@tonic-gate nconf = &conn_polled[conn_index].nc;
14580Sstevel@tonic-gate do_next_conn:;
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate static int
do_poll_cots_action(int fd,int conn_index)14630Sstevel@tonic-gate do_poll_cots_action(int fd, int conn_index)
14640Sstevel@tonic-gate {
14650Sstevel@tonic-gate char buf[256];
14660Sstevel@tonic-gate int event;
14670Sstevel@tonic-gate int i1;
14680Sstevel@tonic-gate int flags;
14690Sstevel@tonic-gate struct conn_entry *connent = &conn_polled[conn_index];
14700Sstevel@tonic-gate struct netconfig *nconf = &(connent->nc);
14710Sstevel@tonic-gate const char *errorstr;
14720Sstevel@tonic-gate
14730Sstevel@tonic-gate while (event = t_look(fd)) {
14740Sstevel@tonic-gate switch (event) {
14750Sstevel@tonic-gate case T_LISTEN:
14760Sstevel@tonic-gate #ifdef DEBUG
14770Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd);
14780Sstevel@tonic-gate #endif
14790Sstevel@tonic-gate cots_listen_event(fd, conn_index);
14800Sstevel@tonic-gate break;
14810Sstevel@tonic-gate
14820Sstevel@tonic-gate case T_DATA:
14830Sstevel@tonic-gate #ifdef DEBUG
14840Sstevel@tonic-gate printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto);
14850Sstevel@tonic-gate #endif
14860Sstevel@tonic-gate /*
14870Sstevel@tonic-gate * Receive a private notification from CONS rpcmod.
14880Sstevel@tonic-gate */
14890Sstevel@tonic-gate i1 = t_rcv(fd, buf, sizeof (buf), &flags);
14900Sstevel@tonic-gate if (i1 == -1) {
14910Sstevel@tonic-gate syslog(LOG_ERR, "t_rcv failed");
14920Sstevel@tonic-gate break;
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate if (i1 < sizeof (int))
14950Sstevel@tonic-gate break;
14960Sstevel@tonic-gate i1 = BE32_TO_U32(buf);
14970Sstevel@tonic-gate if (i1 == 1 || i1 == 2) {
14980Sstevel@tonic-gate /*
14990Sstevel@tonic-gate * This connection has been idle for too long,
15000Sstevel@tonic-gate * so release it as politely as we can. If we
15010Sstevel@tonic-gate * have already initiated an orderly release
15020Sstevel@tonic-gate * and we get notified that the stream is
15030Sstevel@tonic-gate * still idle, pull the plug. This prevents
15040Sstevel@tonic-gate * hung connections from continuing to consume
15050Sstevel@tonic-gate * resources.
15060Sstevel@tonic-gate */
15070Sstevel@tonic-gate #ifdef DEBUG
15080Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd);
15090Sstevel@tonic-gate printf("initiating orderly release of idle connection\n");
15100Sstevel@tonic-gate #endif
15110Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_COTS ||
15127208Svv149972 connent->closing != 0) {
15130Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0);
15140Sstevel@tonic-gate goto fdclose;
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate /*
15170Sstevel@tonic-gate * For NC_TPI_COTS_ORD, the stream is closed
15180Sstevel@tonic-gate * and removed from the poll list when the
15190Sstevel@tonic-gate * T_ORDREL is received from the provider. We
15200Sstevel@tonic-gate * don't wait for it here because it may take
15210Sstevel@tonic-gate * a while for the transport to shut down.
15220Sstevel@tonic-gate */
15230Sstevel@tonic-gate if (t_sndrel(fd) == -1) {
15240Sstevel@tonic-gate syslog(LOG_ERR,
15250Sstevel@tonic-gate "unable to send orderly release %m");
15260Sstevel@tonic-gate }
15270Sstevel@tonic-gate connent->closing = 1;
15280Sstevel@tonic-gate } else
15290Sstevel@tonic-gate syslog(LOG_ERR,
15300Sstevel@tonic-gate "unexpected event from CONS rpcmod %d", i1);
15310Sstevel@tonic-gate break;
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate case T_ORDREL:
15340Sstevel@tonic-gate #ifdef DEBUG
15350Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd);
15360Sstevel@tonic-gate #endif
15370Sstevel@tonic-gate /* Perform an orderly release. */
15380Sstevel@tonic-gate if (t_rcvrel(fd) == 0) {
15390Sstevel@tonic-gate /* T_ORDREL on listen fd's should be ignored */
15400Sstevel@tonic-gate if (!is_listen_fd_index(conn_index)) {
15410Sstevel@tonic-gate (void) t_sndrel(fd);
15420Sstevel@tonic-gate goto fdclose;
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate break;
15450Sstevel@tonic-gate
15460Sstevel@tonic-gate } else if (t_errno == TLOOK) {
15470Sstevel@tonic-gate break;
15480Sstevel@tonic-gate } else {
15490Sstevel@tonic-gate nfslib_log_tli_error("t_rcvrel", fd, nconf);
15500Sstevel@tonic-gate
15510Sstevel@tonic-gate /*
15520Sstevel@tonic-gate * check to make sure we do not close
15530Sstevel@tonic-gate * listen fd
15540Sstevel@tonic-gate */
15550Sstevel@tonic-gate if (is_listen_fd_index(conn_index))
15560Sstevel@tonic-gate break;
15570Sstevel@tonic-gate else
15580Sstevel@tonic-gate goto fdclose;
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate case T_DISCONNECT:
15620Sstevel@tonic-gate #ifdef DEBUG
15630Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd);
15640Sstevel@tonic-gate #endif
15650Sstevel@tonic-gate if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
15660Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf);
15670Sstevel@tonic-gate
15680Sstevel@tonic-gate /*
15690Sstevel@tonic-gate * T_DISCONNECT on listen fd's should be ignored.
15700Sstevel@tonic-gate */
15710Sstevel@tonic-gate if (is_listen_fd_index(conn_index))
15720Sstevel@tonic-gate break;
15730Sstevel@tonic-gate else
15740Sstevel@tonic-gate goto fdclose;
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate case T_ERROR:
15770Sstevel@tonic-gate default:
15780Sstevel@tonic-gate if (event == T_ERROR || t_errno == TSYSERR) {
15797208Svv149972 if ((errorstr = strerror(errno)) == NULL) {
15807208Svv149972 (void) sprintf(buf,
15817208Svv149972 "Unknown error num %d", errno);
15827208Svv149972 errorstr = (const char *) buf;
15837208Svv149972 }
15840Sstevel@tonic-gate } else if (event == -1)
15850Sstevel@tonic-gate errorstr = t_strerror(t_errno);
15860Sstevel@tonic-gate else
15870Sstevel@tonic-gate errorstr = "";
15880Sstevel@tonic-gate syslog(LOG_ERR,
15890Sstevel@tonic-gate "unexpected TLI event (0x%x) on "
15900Sstevel@tonic-gate "connection-oriented transport(%s,%d):%s",
15910Sstevel@tonic-gate event, nconf->nc_proto, fd, errorstr);
15920Sstevel@tonic-gate fdclose:
15930Sstevel@tonic-gate num_conns--;
15940Sstevel@tonic-gate remove_from_poll_list(fd);
15950Sstevel@tonic-gate (void) t_close(fd);
15960Sstevel@tonic-gate return (0);
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate }
15990Sstevel@tonic-gate
16000Sstevel@tonic-gate return (0);
16010Sstevel@tonic-gate }
16020Sstevel@tonic-gate
16030Sstevel@tonic-gate static char *
serv_name_to_port_name(char * name)16040Sstevel@tonic-gate serv_name_to_port_name(char *name)
16050Sstevel@tonic-gate {
16060Sstevel@tonic-gate /*
16070Sstevel@tonic-gate * Map service names (used primarily in logging) to
16080Sstevel@tonic-gate * RPC port names (used by netdir_*() routines).
16090Sstevel@tonic-gate */
16100Sstevel@tonic-gate if (strcmp(name, "NFS") == 0) {
16110Sstevel@tonic-gate return ("nfs");
16120Sstevel@tonic-gate } else if (strcmp(name, "NLM") == 0) {
16130Sstevel@tonic-gate return ("lockd");
16140Sstevel@tonic-gate } else if (strcmp(name, "NFS4_CALLBACK") == 0) {
16150Sstevel@tonic-gate return ("nfs4_callback");
16160Sstevel@tonic-gate }
16170Sstevel@tonic-gate
16180Sstevel@tonic-gate return ("unrecognized");
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate static int
bind_to_provider(char * provider,char * serv,struct netbuf ** addr,struct netconfig ** retnconf)16220Sstevel@tonic-gate bind_to_provider(char *provider, char *serv, struct netbuf **addr,
16230Sstevel@tonic-gate struct netconfig **retnconf)
16240Sstevel@tonic-gate {
16250Sstevel@tonic-gate struct netconfig *nconf;
16260Sstevel@tonic-gate NCONF_HANDLE *nc;
16270Sstevel@tonic-gate struct nd_hostserv hs;
16280Sstevel@tonic-gate
16290Sstevel@tonic-gate hs.h_host = HOST_SELF;
16300Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv);
16310Sstevel@tonic-gate
16320Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
16330Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m");
16340Sstevel@tonic-gate return (-1);
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate while (nconf = getnetconfig(nc)) {
16370Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) &&
16380Sstevel@tonic-gate strcmp(nconf->nc_device, provider) == 0) {
16390Sstevel@tonic-gate *retnconf = nconf;
16400Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs,
16417208Svv149972 listen_backlog));
16420Sstevel@tonic-gate }
16430Sstevel@tonic-gate }
16440Sstevel@tonic-gate (void) endnetconfig(nc);
16450Sstevel@tonic-gate
16460Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
16470Sstevel@tonic-gate provider);
16480Sstevel@tonic-gate return (-1);
16490Sstevel@tonic-gate }
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate static int
bind_to_proto(NETSELDECL (proto),char * serv,struct netbuf ** addr,struct netconfig ** retnconf)16520Sstevel@tonic-gate bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
16530Sstevel@tonic-gate struct netconfig **retnconf)
16540Sstevel@tonic-gate {
16550Sstevel@tonic-gate struct netconfig *nconf;
16560Sstevel@tonic-gate NCONF_HANDLE *nc = NULL;
16570Sstevel@tonic-gate struct nd_hostserv hs;
16580Sstevel@tonic-gate
16590Sstevel@tonic-gate hs.h_host = HOST_SELF;
16600Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv);
16610Sstevel@tonic-gate
16620Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
16630Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m");
16640Sstevel@tonic-gate return (-1);
16650Sstevel@tonic-gate }
16660Sstevel@tonic-gate while (nconf = getnetconfig(nc)) {
16670Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
16680Sstevel@tonic-gate *retnconf = nconf;
16690Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs,
16707208Svv149972 listen_backlog));
16710Sstevel@tonic-gate }
16720Sstevel@tonic-gate }
16730Sstevel@tonic-gate (void) endnetconfig(nc);
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",
16760Sstevel@tonic-gate proto);
16770Sstevel@tonic-gate return (-1);
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate #include <netinet/in.h>
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate /*
16830Sstevel@tonic-gate * Create an address mask appropriate for the transport.
16840Sstevel@tonic-gate * The mask is used to obtain the host-specific part of
16850Sstevel@tonic-gate * a network address when comparing addresses.
16860Sstevel@tonic-gate * For an internet address the host-specific part is just
16870Sstevel@tonic-gate * the 32 bit IP address and this part of the mask is set
16880Sstevel@tonic-gate * to all-ones. The port number part of the mask is zeroes.
16890Sstevel@tonic-gate */
16900Sstevel@tonic-gate static int
set_addrmask(fd,nconf,mask)16910Sstevel@tonic-gate set_addrmask(fd, nconf, mask)
16920Sstevel@tonic-gate struct netconfig *nconf;
16930Sstevel@tonic-gate struct netbuf *mask;
16940Sstevel@tonic-gate {
16950Sstevel@tonic-gate struct t_info info;
16960Sstevel@tonic-gate
16970Sstevel@tonic-gate /*
16980Sstevel@tonic-gate * Find the size of the address we need to mask.
16990Sstevel@tonic-gate */
17000Sstevel@tonic-gate if (t_getinfo(fd, &info) < 0) {
17010Sstevel@tonic-gate t_error("t_getinfo");
17020Sstevel@tonic-gate return (-1);
17030Sstevel@tonic-gate }
17040Sstevel@tonic-gate mask->len = mask->maxlen = info.addr;
17050Sstevel@tonic-gate if (info.addr <= 0) {
17060Sstevel@tonic-gate syslog(LOG_ERR, "set_addrmask: address size: %ld",
17070Sstevel@tonic-gate info.addr);
17080Sstevel@tonic-gate return (-1);
17090Sstevel@tonic-gate }
17100Sstevel@tonic-gate
17110Sstevel@tonic-gate mask->buf = (char *)malloc(mask->len);
17120Sstevel@tonic-gate if (mask->buf == NULL) {
17130Sstevel@tonic-gate syslog(LOG_ERR, "set_addrmask: no memory");
17140Sstevel@tonic-gate return (-1);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */
17170Sstevel@tonic-gate
17180Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
17190Sstevel@tonic-gate /*
17200Sstevel@tonic-gate * Set the mask so that the port is ignored.
17210Sstevel@tonic-gate */
17220Sstevel@tonic-gate /* LINTED pointer alignment */
17230Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
17240Sstevel@tonic-gate (ulong_t)~0;
17250Sstevel@tonic-gate /* LINTED pointer alignment */
17260Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_family =
17270Sstevel@tonic-gate (ushort_t)~0;
17280Sstevel@tonic-gate } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
17290Sstevel@tonic-gate /* LINTED pointer alignment */
17300Sstevel@tonic-gate (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
17310Sstevel@tonic-gate (uchar_t)~0, sizeof (struct in6_addr));
17320Sstevel@tonic-gate /* LINTED pointer alignment */
17330Sstevel@tonic-gate ((struct sockaddr_in6 *)mask->buf)->sin6_family =
17340Sstevel@tonic-gate (ushort_t)~0;
17350Sstevel@tonic-gate } else {
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate /*
17380Sstevel@tonic-gate * Set all mask bits.
17390Sstevel@tonic-gate */
17400Sstevel@tonic-gate (void) memset(mask->buf, 0xFF, mask->len);
17410Sstevel@tonic-gate }
17420Sstevel@tonic-gate return (0);
17430Sstevel@tonic-gate }
17440Sstevel@tonic-gate
17450Sstevel@tonic-gate /*
17460Sstevel@tonic-gate * For listen fd's index is always less than end_listen_fds.
17470Sstevel@tonic-gate * end_listen_fds is defined externally in the daemon that uses this library.
17480Sstevel@tonic-gate * It's value is equal to the number of open file descriptors after the
17490Sstevel@tonic-gate * last listen end point was opened but before any connection was accepted.
17500Sstevel@tonic-gate */
17510Sstevel@tonic-gate static int
is_listen_fd_index(int index)17520Sstevel@tonic-gate is_listen_fd_index(int index)
17530Sstevel@tonic-gate {
17540Sstevel@tonic-gate return (index < end_listen_fds);
17550Sstevel@tonic-gate }
1756