1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* 28*0Sstevel@tonic-gate * nfs_tbind.c, common part for nfsd and lockd. 29*0Sstevel@tonic-gate */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <tiuser.h> 34*0Sstevel@tonic-gate #include <fcntl.h> 35*0Sstevel@tonic-gate #include <netconfig.h> 36*0Sstevel@tonic-gate #include <stropts.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate #include <syslog.h> 39*0Sstevel@tonic-gate #include <rpc/rpc.h> 40*0Sstevel@tonic-gate #include <sys/time.h> 41*0Sstevel@tonic-gate #include <sys/resource.h> 42*0Sstevel@tonic-gate #include <signal.h> 43*0Sstevel@tonic-gate #include <netdir.h> 44*0Sstevel@tonic-gate #include <unistd.h> 45*0Sstevel@tonic-gate #include <string.h> 46*0Sstevel@tonic-gate #include <netinet/tcp.h> 47*0Sstevel@tonic-gate #include <malloc.h> 48*0Sstevel@tonic-gate #include <stdlib.h> 49*0Sstevel@tonic-gate #include "nfs_tbind.h" 50*0Sstevel@tonic-gate #include <nfs/nfs.h> 51*0Sstevel@tonic-gate #include <nfs/nfs_acl.h> 52*0Sstevel@tonic-gate #include <nfs/nfssys.h> 53*0Sstevel@tonic-gate #include <nfs/nfs4.h> 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate /* 56*0Sstevel@tonic-gate * Determine valid semantics for most applications. 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate #define OK_TPI_TYPE(_nconf) \ 59*0Sstevel@tonic-gate (_nconf->nc_semantics == NC_TPI_CLTS || \ 60*0Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS || \ 61*0Sstevel@tonic-gate _nconf->nc_semantics == NC_TPI_COTS_ORD) 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #define BE32_TO_U32(a) \ 64*0Sstevel@tonic-gate ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \ 65*0Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \ 66*0Sstevel@tonic-gate (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \ 67*0Sstevel@tonic-gate ((ulong_t)((uchar_t *)a)[3] & 0xFF)) 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate /* 70*0Sstevel@tonic-gate * Number of elements to add to the poll array on each allocation. 71*0Sstevel@tonic-gate */ 72*0Sstevel@tonic-gate #define POLL_ARRAY_INC_SIZE 64 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate /* 75*0Sstevel@tonic-gate * Number of file descriptors by which the process soft limit may be 76*0Sstevel@tonic-gate * increased on each call to nofile_increase(0). 77*0Sstevel@tonic-gate */ 78*0Sstevel@tonic-gate #define NOFILE_INC_SIZE 64 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate struct conn_ind { 81*0Sstevel@tonic-gate struct conn_ind *conn_next; 82*0Sstevel@tonic-gate struct conn_ind *conn_prev; 83*0Sstevel@tonic-gate struct t_call *conn_call; 84*0Sstevel@tonic-gate }; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate struct conn_entry { 87*0Sstevel@tonic-gate bool_t closing; 88*0Sstevel@tonic-gate struct netconfig nc; 89*0Sstevel@tonic-gate }; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate /* 92*0Sstevel@tonic-gate * this file contains transport routines common to nfsd and lockd 93*0Sstevel@tonic-gate */ 94*0Sstevel@tonic-gate static int nofile_increase(int); 95*0Sstevel@tonic-gate static int reuseaddr(int); 96*0Sstevel@tonic-gate static void add_to_poll_list(int, struct netconfig *); 97*0Sstevel@tonic-gate static char *serv_name_to_port_name(char *); 98*0Sstevel@tonic-gate static int bind_to_proto(char *, char *, struct netbuf **, 99*0Sstevel@tonic-gate struct netconfig **); 100*0Sstevel@tonic-gate static int bind_to_provider(char *, char *, struct netbuf **, 101*0Sstevel@tonic-gate struct netconfig **); 102*0Sstevel@tonic-gate static void conn_close_oldest(void); 103*0Sstevel@tonic-gate static boolean_t conn_get(int, struct netconfig *, struct conn_ind **); 104*0Sstevel@tonic-gate static void cots_listen_event(int, int); 105*0Sstevel@tonic-gate static int discon_get(int, struct netconfig *, struct conn_ind **); 106*0Sstevel@tonic-gate static int do_poll_clts_action(int, int); 107*0Sstevel@tonic-gate static int do_poll_cots_action(int, int); 108*0Sstevel@tonic-gate static void remove_from_poll_list(int); 109*0Sstevel@tonic-gate static int set_addrmask(int, struct netconfig *, struct netbuf *); 110*0Sstevel@tonic-gate static int is_listen_fd_index(int); 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate static struct pollfd *poll_array; 113*0Sstevel@tonic-gate static struct conn_entry *conn_polled; 114*0Sstevel@tonic-gate static int num_conns; /* Current number of connections */ 115*0Sstevel@tonic-gate int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int, 116*0Sstevel@tonic-gate struct netbuf *); 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* 119*0Sstevel@tonic-gate * Called to create and prepare a transport descriptor for in-kernel 120*0Sstevel@tonic-gate * RPC service. 121*0Sstevel@tonic-gate * Returns -1 on failure and a valid descriptor on success. 122*0Sstevel@tonic-gate */ 123*0Sstevel@tonic-gate int 124*0Sstevel@tonic-gate nfslib_transport_open(struct netconfig *nconf) 125*0Sstevel@tonic-gate { 126*0Sstevel@tonic-gate int fd; 127*0Sstevel@tonic-gate struct strioctl strioc; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if ((nconf == (struct netconfig *)NULL) || 130*0Sstevel@tonic-gate (nconf->nc_device == (char *)NULL)) { 131*0Sstevel@tonic-gate syslog(LOG_ERR, "no netconfig device"); 132*0Sstevel@tonic-gate return (-1); 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * Open the transport device. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL); 139*0Sstevel@tonic-gate if (fd == -1) { 140*0Sstevel@tonic-gate if (t_errno == TSYSERR && errno == EMFILE && 141*0Sstevel@tonic-gate (nofile_increase(0) == 0)) { 142*0Sstevel@tonic-gate /* Try again with a higher NOFILE limit. */ 143*0Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, 144*0Sstevel@tonic-gate (struct t_info *)NULL); 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate if (fd == -1) { 147*0Sstevel@tonic-gate syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m", 148*0Sstevel@tonic-gate nconf->nc_device, t_errno); 149*0Sstevel@tonic-gate return (-1); 150*0Sstevel@tonic-gate } 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate /* 154*0Sstevel@tonic-gate * Pop timod because the RPC module must be as close as possible 155*0Sstevel@tonic-gate * to the transport. 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate if (ioctl(fd, I_POP, 0) < 0) { 158*0Sstevel@tonic-gate syslog(LOG_ERR, "I_POP of timod failed: %m"); 159*0Sstevel@tonic-gate (void) t_close(fd); 160*0Sstevel@tonic-gate return (-1); 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate /* 164*0Sstevel@tonic-gate * Common code for CLTS and COTS transports 165*0Sstevel@tonic-gate */ 166*0Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "rpcmod") < 0) { 167*0Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m"); 168*0Sstevel@tonic-gate (void) t_close(fd); 169*0Sstevel@tonic-gate return (-1); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate strioc.ic_cmd = RPC_SERVER; 173*0Sstevel@tonic-gate strioc.ic_dp = (char *)0; 174*0Sstevel@tonic-gate strioc.ic_len = 0; 175*0Sstevel@tonic-gate strioc.ic_timout = -1; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate /* Tell rpcmod to act like a server stream. */ 178*0Sstevel@tonic-gate if (ioctl(fd, I_STR, &strioc) < 0) { 179*0Sstevel@tonic-gate syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m"); 180*0Sstevel@tonic-gate (void) t_close(fd); 181*0Sstevel@tonic-gate return (-1); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * Re-push timod so that we will still be doing TLI 186*0Sstevel@tonic-gate * operations on the descriptor. 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate if (ioctl(fd, I_PUSH, "timod") < 0) { 189*0Sstevel@tonic-gate syslog(LOG_ERR, "I_PUSH of timod failed: %m"); 190*0Sstevel@tonic-gate (void) t_close(fd); 191*0Sstevel@tonic-gate return (-1); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate return (fd); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate static int 198*0Sstevel@tonic-gate nofile_increase(int limit) 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate struct rlimit rl; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { 203*0Sstevel@tonic-gate syslog(LOG_ERR, "getrlimit of NOFILE failed: %m"); 204*0Sstevel@tonic-gate return (-1); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate if (limit > 0) 208*0Sstevel@tonic-gate rl.rlim_cur = limit; 209*0Sstevel@tonic-gate else 210*0Sstevel@tonic-gate rl.rlim_cur += NOFILE_INC_SIZE; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if (rl.rlim_cur > rl.rlim_max && 213*0Sstevel@tonic-gate rl.rlim_max != RLIM_INFINITY) 214*0Sstevel@tonic-gate rl.rlim_max = rl.rlim_cur; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 217*0Sstevel@tonic-gate syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m", 218*0Sstevel@tonic-gate rl.rlim_cur); 219*0Sstevel@tonic-gate return (-1); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate return (0); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate int 226*0Sstevel@tonic-gate nfslib_bindit(struct netconfig *nconf, struct netbuf **addr, 227*0Sstevel@tonic-gate struct nd_hostserv *hs, int backlog) 228*0Sstevel@tonic-gate { 229*0Sstevel@tonic-gate int fd; 230*0Sstevel@tonic-gate struct t_bind *ntb; 231*0Sstevel@tonic-gate struct t_bind tb; 232*0Sstevel@tonic-gate struct nd_addrlist *addrlist; 233*0Sstevel@tonic-gate struct t_optmgmt req, resp; 234*0Sstevel@tonic-gate struct opthdr *opt; 235*0Sstevel@tonic-gate char reqbuf[128]; 236*0Sstevel@tonic-gate bool_t use_any = FALSE; 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate if ((fd = nfslib_transport_open(nconf)) == -1) { 239*0Sstevel@tonic-gate syslog(LOG_ERR, "cannot establish transport service over %s", 240*0Sstevel@tonic-gate nconf->nc_device); 241*0Sstevel@tonic-gate return (-1); 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate addrlist = (struct nd_addrlist *)NULL; 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* nfs4_callback service does not used a fieed port number */ 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate if (strcmp(hs->h_serv, "nfs4_callback") == 0) { 249*0Sstevel@tonic-gate tb.addr.maxlen = 0; 250*0Sstevel@tonic-gate tb.addr.len = 0; 251*0Sstevel@tonic-gate tb.addr.buf = 0; 252*0Sstevel@tonic-gate use_any = TRUE; 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) { 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate syslog(LOG_ERR, 257*0Sstevel@tonic-gate "Cannot get address for transport %s host %s service %s", 258*0Sstevel@tonic-gate nconf->nc_netid, hs->h_host, hs->h_serv); 259*0Sstevel@tonic-gate (void) t_close(fd); 260*0Sstevel@tonic-gate return (-1); 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) { 264*0Sstevel@tonic-gate /* 265*0Sstevel@tonic-gate * If we're running over TCP, then set the 266*0Sstevel@tonic-gate * SO_REUSEADDR option so that we can bind 267*0Sstevel@tonic-gate * to our preferred address even if previously 268*0Sstevel@tonic-gate * left connections exist in FIN_WAIT states. 269*0Sstevel@tonic-gate * This is somewhat bogus, but otherwise you have 270*0Sstevel@tonic-gate * to wait 2 minutes to restart after killing it. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate if (reuseaddr(fd) == -1) { 273*0Sstevel@tonic-gate syslog(LOG_WARNING, 274*0Sstevel@tonic-gate "couldn't set SO_REUSEADDR option on transport"); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_CLTS) 279*0Sstevel@tonic-gate tb.qlen = 0; 280*0Sstevel@tonic-gate else 281*0Sstevel@tonic-gate tb.qlen = backlog; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* LINTED pointer alignment */ 284*0Sstevel@tonic-gate ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL); 285*0Sstevel@tonic-gate if (ntb == (struct t_bind *)NULL) { 286*0Sstevel@tonic-gate syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno); 287*0Sstevel@tonic-gate (void) t_close(fd); 288*0Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 289*0Sstevel@tonic-gate return (-1); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* 293*0Sstevel@tonic-gate * XXX - what about the space tb->addr.buf points to? This should 294*0Sstevel@tonic-gate * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,) 295*0Sstevel@tonic-gate * should't be called with T_ALL. 296*0Sstevel@tonic-gate */ 297*0Sstevel@tonic-gate if (addrlist) 298*0Sstevel@tonic-gate tb.addr = *(addrlist->n_addrs); /* structure copy */ 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate if (t_bind(fd, &tb, ntb) == -1) { 301*0Sstevel@tonic-gate syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno); 302*0Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND); 303*0Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 304*0Sstevel@tonic-gate (void) t_close(fd); 305*0Sstevel@tonic-gate return (-1); 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* make sure we bound to the right address */ 309*0Sstevel@tonic-gate if (use_any == FALSE && 310*0Sstevel@tonic-gate (tb.addr.len != ntb->addr.len || 311*0Sstevel@tonic-gate memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) { 312*0Sstevel@tonic-gate syslog(LOG_ERR, "t_bind to wrong address"); 313*0Sstevel@tonic-gate (void) t_free((char *)ntb, T_BIND); 314*0Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 315*0Sstevel@tonic-gate (void) t_close(fd); 316*0Sstevel@tonic-gate return (-1); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* 320*0Sstevel@tonic-gate * Call nfs4svc_setport so that the kernel can be 321*0Sstevel@tonic-gate * informed what port number the daemon is listing 322*0Sstevel@tonic-gate * for incoming connection requests. 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS || 326*0Sstevel@tonic-gate nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL) 327*0Sstevel@tonic-gate (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr); 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate *addr = &ntb->addr; 330*0Sstevel@tonic-gate netdir_free((void *)addrlist, ND_ADDRLIST); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate if (strcmp(nconf->nc_proto, "tcp") == 0) { 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * Disable the Nagle algorithm on TCP connections. 335*0Sstevel@tonic-gate * Connections accepted from this listener will 336*0Sstevel@tonic-gate * inherit the listener options. 337*0Sstevel@tonic-gate */ 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* LINTED pointer alignment */ 340*0Sstevel@tonic-gate opt = (struct opthdr *)reqbuf; 341*0Sstevel@tonic-gate opt->level = IPPROTO_TCP; 342*0Sstevel@tonic-gate opt->name = TCP_NODELAY; 343*0Sstevel@tonic-gate opt->len = sizeof (int); 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate /* LINTED pointer alignment */ 346*0Sstevel@tonic-gate *(int *)((char *)opt + sizeof (*opt)) = 1; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate req.flags = T_NEGOTIATE; 349*0Sstevel@tonic-gate req.opt.len = sizeof (*opt) + opt->len; 350*0Sstevel@tonic-gate req.opt.buf = (char *)opt; 351*0Sstevel@tonic-gate resp.flags = 0; 352*0Sstevel@tonic-gate resp.opt.buf = reqbuf; 353*0Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || 356*0Sstevel@tonic-gate resp.flags != T_SUCCESS) { 357*0Sstevel@tonic-gate syslog(LOG_ERR, 358*0Sstevel@tonic-gate "couldn't set NODELAY option for proto %s: t_errno = %d, %m", 359*0Sstevel@tonic-gate nconf->nc_proto, t_errno); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate return (fd); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate static int 367*0Sstevel@tonic-gate reuseaddr(int fd) 368*0Sstevel@tonic-gate { 369*0Sstevel@tonic-gate struct t_optmgmt req, resp; 370*0Sstevel@tonic-gate struct opthdr *opt; 371*0Sstevel@tonic-gate char reqbuf[128]; 372*0Sstevel@tonic-gate int *ip; 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* LINTED pointer alignment */ 375*0Sstevel@tonic-gate opt = (struct opthdr *)reqbuf; 376*0Sstevel@tonic-gate opt->level = SOL_SOCKET; 377*0Sstevel@tonic-gate opt->name = SO_REUSEADDR; 378*0Sstevel@tonic-gate opt->len = sizeof (int); 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* LINTED pointer alignment */ 381*0Sstevel@tonic-gate ip = (int *)&reqbuf[sizeof (struct opthdr)]; 382*0Sstevel@tonic-gate *ip = 1; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate req.flags = T_NEGOTIATE; 385*0Sstevel@tonic-gate req.opt.len = sizeof (struct opthdr) + opt->len; 386*0Sstevel@tonic-gate req.opt.buf = (char *)opt; 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate resp.flags = 0; 389*0Sstevel@tonic-gate resp.opt.buf = reqbuf; 390*0Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 393*0Sstevel@tonic-gate t_error("t_optmgmt"); 394*0Sstevel@tonic-gate return (-1); 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate return (0); 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate void 400*0Sstevel@tonic-gate nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf) 401*0Sstevel@tonic-gate { 402*0Sstevel@tonic-gate int error; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate /* 405*0Sstevel@tonic-gate * Save the error code across syslog(), just in case syslog() 406*0Sstevel@tonic-gate * gets its own error and, therefore, overwrites errno. 407*0Sstevel@tonic-gate */ 408*0Sstevel@tonic-gate error = errno; 409*0Sstevel@tonic-gate if (t_errno == TSYSERR) { 410*0Sstevel@tonic-gate syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m", 411*0Sstevel@tonic-gate tli_name, fd, nconf->nc_proto); 412*0Sstevel@tonic-gate } else { 413*0Sstevel@tonic-gate syslog(LOG_ERR, 414*0Sstevel@tonic-gate "%s(file descriptor %d/transport %s) TLI error %d", 415*0Sstevel@tonic-gate tli_name, fd, nconf->nc_proto, t_errno); 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate errno = error; 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate /* 421*0Sstevel@tonic-gate * Called to set up service over a particular transport. 422*0Sstevel@tonic-gate */ 423*0Sstevel@tonic-gate void 424*0Sstevel@tonic-gate do_one(char *provider, NETSELDECL(proto), struct protob *protobp0, 425*0Sstevel@tonic-gate int (*svc)(int, struct netbuf, struct netconfig *)) 426*0Sstevel@tonic-gate { 427*0Sstevel@tonic-gate register int sock; 428*0Sstevel@tonic-gate struct protob *protobp; 429*0Sstevel@tonic-gate struct netbuf *retaddr; 430*0Sstevel@tonic-gate struct netconfig *retnconf; 431*0Sstevel@tonic-gate struct netbuf addrmask; 432*0Sstevel@tonic-gate int vers; 433*0Sstevel@tonic-gate int err; 434*0Sstevel@tonic-gate int l; 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate if (provider) 437*0Sstevel@tonic-gate sock = bind_to_provider(provider, protobp0->serv, &retaddr, 438*0Sstevel@tonic-gate &retnconf); 439*0Sstevel@tonic-gate else 440*0Sstevel@tonic-gate sock = bind_to_proto(proto, protobp0->serv, &retaddr, 441*0Sstevel@tonic-gate &retnconf); 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate if (sock == -1) { 444*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 445*0Sstevel@tonic-gate "Cannot establish %s service over %s: transport setup problem.", 446*0Sstevel@tonic-gate protobp0->serv, provider ? provider : proto); 447*0Sstevel@tonic-gate return; 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate if (set_addrmask(sock, retnconf, &addrmask) < 0) { 451*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 452*0Sstevel@tonic-gate "Cannot set address mask for %s", retnconf->nc_netid); 453*0Sstevel@tonic-gate return; 454*0Sstevel@tonic-gate } 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate /* 457*0Sstevel@tonic-gate * Register all versions of the programs in the protocol block list. 458*0Sstevel@tonic-gate */ 459*0Sstevel@tonic-gate l = strlen(NC_UDP); 460*0Sstevel@tonic-gate for (protobp = protobp0; protobp; protobp = protobp->next) { 461*0Sstevel@tonic-gate for (vers = protobp->versmin; vers <= protobp->versmax; 462*0Sstevel@tonic-gate vers++) { 463*0Sstevel@tonic-gate if ((protobp->program == NFS_PROGRAM || 464*0Sstevel@tonic-gate protobp->program == NFS_ACL_PROGRAM) && 465*0Sstevel@tonic-gate vers == NFS_V4 && 466*0Sstevel@tonic-gate strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0) 467*0Sstevel@tonic-gate continue; 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate (void) rpcb_unset(protobp->program, vers, retnconf); 470*0Sstevel@tonic-gate (void) rpcb_set(protobp->program, vers, retnconf, 471*0Sstevel@tonic-gate retaddr); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate if (retnconf->nc_semantics == NC_TPI_CLTS) { 476*0Sstevel@tonic-gate /* Don't drop core if supporting module(s) aren't loaded. */ 477*0Sstevel@tonic-gate (void) signal(SIGSYS, SIG_IGN); 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * svc() doesn't block, it returns success or failure. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate if (svc == NULL && Mysvc4 != NULL) 484*0Sstevel@tonic-gate err = (*Mysvc4)(sock, &addrmask, retnconf, 485*0Sstevel@tonic-gate NFS4_SETPORT|NFS4_KRPC_START, retaddr); 486*0Sstevel@tonic-gate else 487*0Sstevel@tonic-gate err = (*svc)(sock, addrmask, retnconf); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate if (err < 0) { 490*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 491*0Sstevel@tonic-gate "Cannot establish %s service over <file desc." 492*0Sstevel@tonic-gate " %d, protocol %s> : %m. Exiting", 493*0Sstevel@tonic-gate protobp0->serv, sock, retnconf->nc_proto); 494*0Sstevel@tonic-gate exit(1); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate /* 499*0Sstevel@tonic-gate * We successfully set up the server over this transport. 500*0Sstevel@tonic-gate * Add this descriptor to the one being polled on. 501*0Sstevel@tonic-gate */ 502*0Sstevel@tonic-gate add_to_poll_list(sock, retnconf); 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate /* 505*0Sstevel@tonic-gate * Set up the NFS service over all the available transports. 506*0Sstevel@tonic-gate * Returns -1 for failure, 0 for success. 507*0Sstevel@tonic-gate */ 508*0Sstevel@tonic-gate int 509*0Sstevel@tonic-gate do_all(struct protob *protobp, 510*0Sstevel@tonic-gate int (*svc)(int, struct netbuf, struct netconfig *)) 511*0Sstevel@tonic-gate { 512*0Sstevel@tonic-gate struct netconfig *nconf; 513*0Sstevel@tonic-gate NCONF_HANDLE *nc; 514*0Sstevel@tonic-gate int l; 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 517*0Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 518*0Sstevel@tonic-gate return (-1); 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate l = strlen(NC_UDP); 521*0Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 522*0Sstevel@tonic-gate if ((nconf->nc_flag & NC_VISIBLE) && 523*0Sstevel@tonic-gate strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 && 524*0Sstevel@tonic-gate OK_TPI_TYPE(nconf) && 525*0Sstevel@tonic-gate (protobp->program != NFS4_CALLBACK || 526*0Sstevel@tonic-gate strncasecmp(nconf->nc_proto, NC_UDP, l) != 0)) 527*0Sstevel@tonic-gate do_one(nconf->nc_device, nconf->nc_proto, 528*0Sstevel@tonic-gate protobp, svc); 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate (void) endnetconfig(nc); 531*0Sstevel@tonic-gate return (0); 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate /* 535*0Sstevel@tonic-gate * poll on the open transport descriptors for events and errors. 536*0Sstevel@tonic-gate */ 537*0Sstevel@tonic-gate void 538*0Sstevel@tonic-gate poll_for_action(void) 539*0Sstevel@tonic-gate { 540*0Sstevel@tonic-gate int nfds; 541*0Sstevel@tonic-gate int i; 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* 544*0Sstevel@tonic-gate * Keep polling until all transports have been closed. When this 545*0Sstevel@tonic-gate * happens, we return. 546*0Sstevel@tonic-gate */ 547*0Sstevel@tonic-gate while ((int)num_fds > 0) { 548*0Sstevel@tonic-gate nfds = poll(poll_array, num_fds, INFTIM); 549*0Sstevel@tonic-gate switch (nfds) { 550*0Sstevel@tonic-gate case 0: 551*0Sstevel@tonic-gate continue; 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate case -1: 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * Some errors from poll could be 556*0Sstevel@tonic-gate * due to temporary conditions, and we try to 557*0Sstevel@tonic-gate * be robust in the face of them. Other 558*0Sstevel@tonic-gate * errors (should never happen in theory) 559*0Sstevel@tonic-gate * are fatal (eg. EINVAL, EFAULT). 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate switch (errno) { 562*0Sstevel@tonic-gate case EINTR: 563*0Sstevel@tonic-gate continue; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate case EAGAIN: 566*0Sstevel@tonic-gate case ENOMEM: 567*0Sstevel@tonic-gate (void) sleep(10); 568*0Sstevel@tonic-gate continue; 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate default: 571*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 572*0Sstevel@tonic-gate "poll failed: %m. Exiting"); 573*0Sstevel@tonic-gate exit(1); 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate default: 576*0Sstevel@tonic-gate break; 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate /* 580*0Sstevel@tonic-gate * Go through the poll list looking for events. 581*0Sstevel@tonic-gate */ 582*0Sstevel@tonic-gate for (i = 0; i < num_fds && nfds > 0; i++) { 583*0Sstevel@tonic-gate if (poll_array[i].revents) { 584*0Sstevel@tonic-gate nfds--; 585*0Sstevel@tonic-gate /* 586*0Sstevel@tonic-gate * We have a message, so try to read it. 587*0Sstevel@tonic-gate * Record the error return in errno, 588*0Sstevel@tonic-gate * so that syslog(LOG_ERR, "...%m") 589*0Sstevel@tonic-gate * dumps the corresponding error string. 590*0Sstevel@tonic-gate */ 591*0Sstevel@tonic-gate if (conn_polled[i].nc.nc_semantics == 592*0Sstevel@tonic-gate NC_TPI_CLTS) { 593*0Sstevel@tonic-gate errno = do_poll_clts_action( 594*0Sstevel@tonic-gate poll_array[i].fd, i); 595*0Sstevel@tonic-gate } else { 596*0Sstevel@tonic-gate errno = do_poll_cots_action( 597*0Sstevel@tonic-gate poll_array[i].fd, i); 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate if (errno == 0) 601*0Sstevel@tonic-gate continue; 602*0Sstevel@tonic-gate /* 603*0Sstevel@tonic-gate * Most returned error codes mean that there is 604*0Sstevel@tonic-gate * fatal condition which we can only deal with 605*0Sstevel@tonic-gate * by closing the transport. 606*0Sstevel@tonic-gate */ 607*0Sstevel@tonic-gate if (errno != EAGAIN && errno != ENOMEM) { 608*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 609*0Sstevel@tonic-gate "Error (%m) reading descriptor %d/transport %s. Closing it.", 610*0Sstevel@tonic-gate poll_array[i].fd, 611*0Sstevel@tonic-gate conn_polled[i].nc.nc_proto); 612*0Sstevel@tonic-gate (void) t_close(poll_array[i].fd); 613*0Sstevel@tonic-gate remove_from_poll_list(poll_array[i].fd); 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate } else if (errno == ENOMEM) 616*0Sstevel@tonic-gate (void) sleep(5); 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 622*0Sstevel@tonic-gate "All transports have been closed with errors. Exiting."); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* 626*0Sstevel@tonic-gate * Allocate poll/transport array entries for this descriptor. 627*0Sstevel@tonic-gate */ 628*0Sstevel@tonic-gate static void 629*0Sstevel@tonic-gate add_to_poll_list(int fd, struct netconfig *nconf) 630*0Sstevel@tonic-gate { 631*0Sstevel@tonic-gate static int poll_array_size = 0; 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * If the arrays are full, allocate new ones. 635*0Sstevel@tonic-gate */ 636*0Sstevel@tonic-gate if (num_fds == poll_array_size) { 637*0Sstevel@tonic-gate struct pollfd *tpa; 638*0Sstevel@tonic-gate struct conn_entry *tnp; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate if (poll_array_size != 0) { 641*0Sstevel@tonic-gate tpa = poll_array; 642*0Sstevel@tonic-gate tnp = conn_polled; 643*0Sstevel@tonic-gate } else 644*0Sstevel@tonic-gate tpa = (struct pollfd *)0; 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate poll_array_size += POLL_ARRAY_INC_SIZE; 647*0Sstevel@tonic-gate /* 648*0Sstevel@tonic-gate * Allocate new arrays. 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate poll_array = (struct pollfd *) 651*0Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct pollfd) + 256); 652*0Sstevel@tonic-gate conn_polled = (struct conn_entry *) 653*0Sstevel@tonic-gate malloc(poll_array_size * sizeof (struct conn_entry) + 256); 654*0Sstevel@tonic-gate if (poll_array == (struct pollfd *)NULL || 655*0Sstevel@tonic-gate conn_polled == (struct conn_entry *)NULL) { 656*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc failed for poll array"); 657*0Sstevel@tonic-gate exit(1); 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate /* 661*0Sstevel@tonic-gate * Copy the data of the old ones into new arrays, and 662*0Sstevel@tonic-gate * free the old ones. 663*0Sstevel@tonic-gate */ 664*0Sstevel@tonic-gate if (tpa) { 665*0Sstevel@tonic-gate (void) memcpy((void *)poll_array, (void *)tpa, 666*0Sstevel@tonic-gate num_fds * sizeof (struct pollfd)); 667*0Sstevel@tonic-gate (void) memcpy((void *)conn_polled, (void *)tnp, 668*0Sstevel@tonic-gate num_fds * sizeof (struct conn_entry)); 669*0Sstevel@tonic-gate free((void *)tpa); 670*0Sstevel@tonic-gate free((void *)tnp); 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate } 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate /* 675*0Sstevel@tonic-gate * Set the descriptor and event list. All possible events are 676*0Sstevel@tonic-gate * polled for. 677*0Sstevel@tonic-gate */ 678*0Sstevel@tonic-gate poll_array[num_fds].fd = fd; 679*0Sstevel@tonic-gate poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate /* 682*0Sstevel@tonic-gate * Copy the transport data over too. 683*0Sstevel@tonic-gate */ 684*0Sstevel@tonic-gate conn_polled[num_fds].nc = *nconf; 685*0Sstevel@tonic-gate conn_polled[num_fds].closing = 0; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate /* 688*0Sstevel@tonic-gate * Set the descriptor to non-blocking. Avoids a race 689*0Sstevel@tonic-gate * between data arriving on the stream and then having it 690*0Sstevel@tonic-gate * flushed before we can read it. 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 693*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 694*0Sstevel@tonic-gate "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting", 695*0Sstevel@tonic-gate num_fds, nconf->nc_proto); 696*0Sstevel@tonic-gate exit(1); 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate /* 700*0Sstevel@tonic-gate * Count this descriptor. 701*0Sstevel@tonic-gate */ 702*0Sstevel@tonic-gate ++num_fds; 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate static void 706*0Sstevel@tonic-gate remove_from_poll_list(int fd) 707*0Sstevel@tonic-gate { 708*0Sstevel@tonic-gate int i; 709*0Sstevel@tonic-gate int num_to_copy; 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate for (i = 0; i < num_fds; i++) { 712*0Sstevel@tonic-gate if (poll_array[i].fd == fd) { 713*0Sstevel@tonic-gate --num_fds; 714*0Sstevel@tonic-gate num_to_copy = num_fds - i; 715*0Sstevel@tonic-gate (void) memcpy((void *)&poll_array[i], 716*0Sstevel@tonic-gate (void *)&poll_array[i+1], 717*0Sstevel@tonic-gate num_to_copy * sizeof (struct pollfd)); 718*0Sstevel@tonic-gate (void) memset((void *)&poll_array[num_fds], 0, 719*0Sstevel@tonic-gate sizeof (struct pollfd)); 720*0Sstevel@tonic-gate (void) memcpy((void *)&conn_polled[i], 721*0Sstevel@tonic-gate (void *)&conn_polled[i+1], 722*0Sstevel@tonic-gate num_to_copy * sizeof (struct conn_entry)); 723*0Sstevel@tonic-gate (void) memset((void *)&conn_polled[num_fds], 0, 724*0Sstevel@tonic-gate sizeof (struct conn_entry)); 725*0Sstevel@tonic-gate return; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list"); 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate } 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate /* 733*0Sstevel@tonic-gate * Called to read and interpret the event on a connectionless descriptor. 734*0Sstevel@tonic-gate * Returns 0 if successful, or a UNIX error code if failure. 735*0Sstevel@tonic-gate */ 736*0Sstevel@tonic-gate static int 737*0Sstevel@tonic-gate do_poll_clts_action(int fd, int conn_index) 738*0Sstevel@tonic-gate { 739*0Sstevel@tonic-gate int error; 740*0Sstevel@tonic-gate int ret; 741*0Sstevel@tonic-gate int flags; 742*0Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc; 743*0Sstevel@tonic-gate static struct t_unitdata *unitdata = NULL; 744*0Sstevel@tonic-gate static struct t_uderr *uderr = NULL; 745*0Sstevel@tonic-gate static int oldfd = -1; 746*0Sstevel@tonic-gate struct nd_hostservlist *host = NULL; 747*0Sstevel@tonic-gate struct strbuf ctl[1], data[1]; 748*0Sstevel@tonic-gate /* 749*0Sstevel@tonic-gate * We just need to have some space to consume the 750*0Sstevel@tonic-gate * message in the event we can't use the TLI interface to do the 751*0Sstevel@tonic-gate * job. 752*0Sstevel@tonic-gate * 753*0Sstevel@tonic-gate * We flush the message using getmsg(). For the control part 754*0Sstevel@tonic-gate * we allocate enough for any TPI header plus 32 bytes for address 755*0Sstevel@tonic-gate * and options. For the data part, there is nothing magic about 756*0Sstevel@tonic-gate * the size of the array, but 256 bytes is probably better than 757*0Sstevel@tonic-gate * 1 byte, and we don't expect any data portion anyway. 758*0Sstevel@tonic-gate * 759*0Sstevel@tonic-gate * If the array sizes are too small, we handle this because getmsg() 760*0Sstevel@tonic-gate * (called to consume the message) will return MOREDATA|MORECTL. 761*0Sstevel@tonic-gate * Thus we just call getmsg() until it's read the message. 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate char ctlbuf[sizeof (union T_primitives) + 32]; 764*0Sstevel@tonic-gate char databuf[256]; 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate /* 767*0Sstevel@tonic-gate * If this is the same descriptor as the last time 768*0Sstevel@tonic-gate * do_poll_clts_action was called, we can save some 769*0Sstevel@tonic-gate * de-allocation and allocation. 770*0Sstevel@tonic-gate */ 771*0Sstevel@tonic-gate if (oldfd != fd) { 772*0Sstevel@tonic-gate oldfd = fd; 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate if (unitdata) { 775*0Sstevel@tonic-gate (void) t_free((char *)unitdata, T_UNITDATA); 776*0Sstevel@tonic-gate unitdata = NULL; 777*0Sstevel@tonic-gate } 778*0Sstevel@tonic-gate if (uderr) { 779*0Sstevel@tonic-gate (void) t_free((char *)uderr, T_UDERROR); 780*0Sstevel@tonic-gate uderr = NULL; 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate /* 785*0Sstevel@tonic-gate * Allocate a unitdata structure for receiving the event. 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate if (unitdata == NULL) { 788*0Sstevel@tonic-gate /* LINTED pointer alignment */ 789*0Sstevel@tonic-gate unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL); 790*0Sstevel@tonic-gate if (unitdata == NULL) { 791*0Sstevel@tonic-gate if (t_errno == TSYSERR) { 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * Save the error code across 794*0Sstevel@tonic-gate * syslog(), just in case 795*0Sstevel@tonic-gate * syslog() gets its own error 796*0Sstevel@tonic-gate * and therefore overwrites errno. 797*0Sstevel@tonic-gate */ 798*0Sstevel@tonic-gate error = errno; 799*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 800*0Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m", 801*0Sstevel@tonic-gate fd, nconf->nc_proto); 802*0Sstevel@tonic-gate return (error); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 805*0Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d", 806*0Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 807*0Sstevel@tonic-gate goto flush_it; 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate try_again: 812*0Sstevel@tonic-gate flags = 0; 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate /* 815*0Sstevel@tonic-gate * The idea is we wait for T_UNITDATA_IND's. Of course, 816*0Sstevel@tonic-gate * we don't get any, because rpcmod filters them out. 817*0Sstevel@tonic-gate * However, we need to call t_rcvudata() to let TLI 818*0Sstevel@tonic-gate * tell us we have a T_UDERROR_IND. 819*0Sstevel@tonic-gate * 820*0Sstevel@tonic-gate * algorithm is: 821*0Sstevel@tonic-gate * t_rcvudata(), expecting TLOOK. 822*0Sstevel@tonic-gate * t_look(), expecting T_UDERR. 823*0Sstevel@tonic-gate * t_rcvuderr(), expecting success (0). 824*0Sstevel@tonic-gate * expand destination address into ASCII, 825*0Sstevel@tonic-gate * and dump it. 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate ret = t_rcvudata(fd, unitdata, &flags); 829*0Sstevel@tonic-gate if (ret == 0 || t_errno == TBUFOVFLW) { 830*0Sstevel@tonic-gate (void) syslog(LOG_WARNING, 831*0Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes", 832*0Sstevel@tonic-gate fd, nconf->nc_proto, unitdata->udata.len); 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate /* 835*0Sstevel@tonic-gate * Even though we don't expect any data, in case we do, 836*0Sstevel@tonic-gate * keep reading until there is no more. 837*0Sstevel@tonic-gate */ 838*0Sstevel@tonic-gate if (flags & T_MORE) 839*0Sstevel@tonic-gate goto try_again; 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate return (0); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate switch (t_errno) { 845*0Sstevel@tonic-gate case TNODATA: 846*0Sstevel@tonic-gate return (0); 847*0Sstevel@tonic-gate case TSYSERR: 848*0Sstevel@tonic-gate /* 849*0Sstevel@tonic-gate * System errors are returned to caller. 850*0Sstevel@tonic-gate * Save the error code across 851*0Sstevel@tonic-gate * syslog(), just in case 852*0Sstevel@tonic-gate * syslog() gets its own error 853*0Sstevel@tonic-gate * and therefore overwrites errno. 854*0Sstevel@tonic-gate */ 855*0Sstevel@tonic-gate error = errno; 856*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 857*0Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) %m", 858*0Sstevel@tonic-gate fd, nconf->nc_proto); 859*0Sstevel@tonic-gate return (error); 860*0Sstevel@tonic-gate case TLOOK: 861*0Sstevel@tonic-gate break; 862*0Sstevel@tonic-gate default: 863*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 864*0Sstevel@tonic-gate "t_rcvudata(file descriptor %d/transport %s) TLI error %d", 865*0Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 866*0Sstevel@tonic-gate goto flush_it; 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate ret = t_look(fd); 870*0Sstevel@tonic-gate switch (ret) { 871*0Sstevel@tonic-gate case 0: 872*0Sstevel@tonic-gate return (0); 873*0Sstevel@tonic-gate case -1: 874*0Sstevel@tonic-gate /* 875*0Sstevel@tonic-gate * System errors are returned to caller. 876*0Sstevel@tonic-gate */ 877*0Sstevel@tonic-gate if (t_errno == TSYSERR) { 878*0Sstevel@tonic-gate /* 879*0Sstevel@tonic-gate * Save the error code across 880*0Sstevel@tonic-gate * syslog(), just in case 881*0Sstevel@tonic-gate * syslog() gets its own error 882*0Sstevel@tonic-gate * and therefore overwrites errno. 883*0Sstevel@tonic-gate */ 884*0Sstevel@tonic-gate error = errno; 885*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 886*0Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) %m", 887*0Sstevel@tonic-gate fd, nconf->nc_proto); 888*0Sstevel@tonic-gate return (error); 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 891*0Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) TLI error %d", 892*0Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 893*0Sstevel@tonic-gate goto flush_it; 894*0Sstevel@tonic-gate case T_UDERR: 895*0Sstevel@tonic-gate break; 896*0Sstevel@tonic-gate default: 897*0Sstevel@tonic-gate (void) syslog(LOG_WARNING, 898*0Sstevel@tonic-gate "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)", 899*0Sstevel@tonic-gate fd, nconf->nc_proto, ret, T_UDERR); 900*0Sstevel@tonic-gate } 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate if (uderr == NULL) { 903*0Sstevel@tonic-gate /* LINTED pointer alignment */ 904*0Sstevel@tonic-gate uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL); 905*0Sstevel@tonic-gate if (uderr == NULL) { 906*0Sstevel@tonic-gate if (t_errno == TSYSERR) { 907*0Sstevel@tonic-gate /* 908*0Sstevel@tonic-gate * Save the error code across 909*0Sstevel@tonic-gate * syslog(), just in case 910*0Sstevel@tonic-gate * syslog() gets its own error 911*0Sstevel@tonic-gate * and therefore overwrites errno. 912*0Sstevel@tonic-gate */ 913*0Sstevel@tonic-gate error = errno; 914*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 915*0Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m", 916*0Sstevel@tonic-gate fd, nconf->nc_proto); 917*0Sstevel@tonic-gate return (error); 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 920*0Sstevel@tonic-gate "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d", 921*0Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 922*0Sstevel@tonic-gate goto flush_it; 923*0Sstevel@tonic-gate } 924*0Sstevel@tonic-gate } 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate ret = t_rcvuderr(fd, uderr); 927*0Sstevel@tonic-gate if (ret == 0) { 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate /* 930*0Sstevel@tonic-gate * Save the datagram error in errno, so that the 931*0Sstevel@tonic-gate * %m argument to syslog picks up the error string. 932*0Sstevel@tonic-gate */ 933*0Sstevel@tonic-gate errno = uderr->error; 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate /* 936*0Sstevel@tonic-gate * Log the datagram error, then log the host that 937*0Sstevel@tonic-gate * probably triggerred. Cannot log both in the 938*0Sstevel@tonic-gate * same transaction because of packet size limitations 939*0Sstevel@tonic-gate * in /dev/log. 940*0Sstevel@tonic-gate */ 941*0Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 942*0Sstevel@tonic-gate "NFS response over <file descriptor %d/transport %s> generated error: %m", 943*0Sstevel@tonic-gate fd, nconf->nc_proto); 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate /* 946*0Sstevel@tonic-gate * Try to map the client's address back to a 947*0Sstevel@tonic-gate * name. 948*0Sstevel@tonic-gate */ 949*0Sstevel@tonic-gate ret = netdir_getbyaddr(nconf, &host, &uderr->addr); 950*0Sstevel@tonic-gate if (ret != -1 && host && host->h_cnt > 0 && 951*0Sstevel@tonic-gate host->h_hostservs) { 952*0Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 953*0Sstevel@tonic-gate "Bad NFS response was sent to client with host name: %s; service port: %s", 954*0Sstevel@tonic-gate host->h_hostservs->h_host, 955*0Sstevel@tonic-gate host->h_hostservs->h_serv); 956*0Sstevel@tonic-gate } else { 957*0Sstevel@tonic-gate int i, j; 958*0Sstevel@tonic-gate char *buf; 959*0Sstevel@tonic-gate char *hex = "0123456789abcdef"; 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate /* 962*0Sstevel@tonic-gate * Mapping failed, print the whole thing 963*0Sstevel@tonic-gate * in ASCII hex. 964*0Sstevel@tonic-gate */ 965*0Sstevel@tonic-gate buf = (char *)malloc(uderr->addr.len * 2 + 1); 966*0Sstevel@tonic-gate for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) { 967*0Sstevel@tonic-gate buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf]; 968*0Sstevel@tonic-gate buf[j+1] = hex[uderr->addr.buf[i] & 0xf]; 969*0Sstevel@tonic-gate } 970*0Sstevel@tonic-gate buf[j] = '\0'; 971*0Sstevel@tonic-gate (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING, 972*0Sstevel@tonic-gate "Bad NFS response was sent to client with transport address: 0x%s", 973*0Sstevel@tonic-gate buf); 974*0Sstevel@tonic-gate free((void *)buf); 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate if (ret == 0 && host != NULL) 978*0Sstevel@tonic-gate netdir_free((void *)host, ND_HOSTSERVLIST); 979*0Sstevel@tonic-gate return (0); 980*0Sstevel@tonic-gate } 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate switch (t_errno) { 983*0Sstevel@tonic-gate case TNOUDERR: 984*0Sstevel@tonic-gate goto flush_it; 985*0Sstevel@tonic-gate case TSYSERR: 986*0Sstevel@tonic-gate /* 987*0Sstevel@tonic-gate * System errors are returned to caller. 988*0Sstevel@tonic-gate * Save the error code across 989*0Sstevel@tonic-gate * syslog(), just in case 990*0Sstevel@tonic-gate * syslog() gets its own error 991*0Sstevel@tonic-gate * and therefore overwrites errno. 992*0Sstevel@tonic-gate */ 993*0Sstevel@tonic-gate error = errno; 994*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 995*0Sstevel@tonic-gate "t_rcvuderr(file descriptor %d/transport %s) %m", 996*0Sstevel@tonic-gate fd, nconf->nc_proto); 997*0Sstevel@tonic-gate return (error); 998*0Sstevel@tonic-gate default: 999*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 1000*0Sstevel@tonic-gate "t_rcvuderr(file descriptor %d/transport %s) TLI error %d", 1001*0Sstevel@tonic-gate fd, nconf->nc_proto, t_errno); 1002*0Sstevel@tonic-gate goto flush_it; 1003*0Sstevel@tonic-gate } 1004*0Sstevel@tonic-gate 1005*0Sstevel@tonic-gate flush_it: 1006*0Sstevel@tonic-gate /* 1007*0Sstevel@tonic-gate * If we get here, then we could not cope with whatever message 1008*0Sstevel@tonic-gate * we attempted to read, so flush it. If we did read a message, 1009*0Sstevel@tonic-gate * and one isn't present, that is all right, because fd is in 1010*0Sstevel@tonic-gate * nonblocking mode. 1011*0Sstevel@tonic-gate */ 1012*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 1013*0Sstevel@tonic-gate "Flushing one input message from <file descriptor %d/transport %s>", 1014*0Sstevel@tonic-gate fd, nconf->nc_proto); 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate /* 1017*0Sstevel@tonic-gate * Read and discard the message. Do this this until there is 1018*0Sstevel@tonic-gate * no more control/data in the message or until we get an error. 1019*0Sstevel@tonic-gate */ 1020*0Sstevel@tonic-gate do { 1021*0Sstevel@tonic-gate ctl->maxlen = sizeof (ctlbuf); 1022*0Sstevel@tonic-gate ctl->buf = ctlbuf; 1023*0Sstevel@tonic-gate data->maxlen = sizeof (databuf); 1024*0Sstevel@tonic-gate data->buf = databuf; 1025*0Sstevel@tonic-gate flags = 0; 1026*0Sstevel@tonic-gate ret = getmsg(fd, ctl, data, &flags); 1027*0Sstevel@tonic-gate if (ret == -1) 1028*0Sstevel@tonic-gate return (errno); 1029*0Sstevel@tonic-gate } while (ret != 0); 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate return (0); 1032*0Sstevel@tonic-gate } 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate static void 1035*0Sstevel@tonic-gate conn_close_oldest(void) 1036*0Sstevel@tonic-gate { 1037*0Sstevel@tonic-gate int fd; 1038*0Sstevel@tonic-gate int i1; 1039*0Sstevel@tonic-gate 1040*0Sstevel@tonic-gate /* 1041*0Sstevel@tonic-gate * Find the oldest connection that is not already in the 1042*0Sstevel@tonic-gate * process of shutting down. 1043*0Sstevel@tonic-gate */ 1044*0Sstevel@tonic-gate for (i1 = end_listen_fds; /* no conditional expression */; i1++) { 1045*0Sstevel@tonic-gate if (i1 >= num_fds) 1046*0Sstevel@tonic-gate return; 1047*0Sstevel@tonic-gate if (conn_polled[i1].closing == 0) 1048*0Sstevel@tonic-gate break; 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate #ifdef DEBUG 1051*0Sstevel@tonic-gate printf("too many connections (%d), releasing oldest (%d)\n", 1052*0Sstevel@tonic-gate num_conns, poll_array[i1].fd); 1053*0Sstevel@tonic-gate #else 1054*0Sstevel@tonic-gate syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)", 1055*0Sstevel@tonic-gate num_conns, poll_array[i1].fd); 1056*0Sstevel@tonic-gate #endif 1057*0Sstevel@tonic-gate fd = poll_array[i1].fd; 1058*0Sstevel@tonic-gate if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) { 1059*0Sstevel@tonic-gate /* 1060*0Sstevel@tonic-gate * For politeness, send a T_DISCON_REQ to the transport 1061*0Sstevel@tonic-gate * provider. We close the stream anyway. 1062*0Sstevel@tonic-gate */ 1063*0Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0); 1064*0Sstevel@tonic-gate num_conns--; 1065*0Sstevel@tonic-gate remove_from_poll_list(fd); 1066*0Sstevel@tonic-gate (void) t_close(fd); 1067*0Sstevel@tonic-gate } else { 1068*0Sstevel@tonic-gate /* 1069*0Sstevel@tonic-gate * For orderly release, we do not close the stream 1070*0Sstevel@tonic-gate * until the T_ORDREL_IND arrives to complete 1071*0Sstevel@tonic-gate * the handshake. 1072*0Sstevel@tonic-gate */ 1073*0Sstevel@tonic-gate if (t_sndrel(fd) == 0) 1074*0Sstevel@tonic-gate conn_polled[i1].closing = 1; 1075*0Sstevel@tonic-gate } 1076*0Sstevel@tonic-gate } 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate static boolean_t 1079*0Sstevel@tonic-gate conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 1080*0Sstevel@tonic-gate { 1081*0Sstevel@tonic-gate struct conn_ind *conn; 1082*0Sstevel@tonic-gate struct conn_ind *next_conn; 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate conn = (struct conn_ind *)malloc(sizeof (*conn)); 1085*0Sstevel@tonic-gate if (conn == NULL) { 1086*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc for listen indication failed"); 1087*0Sstevel@tonic-gate return (FALSE); 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate 1090*0Sstevel@tonic-gate /* LINTED pointer alignment */ 1091*0Sstevel@tonic-gate conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); 1092*0Sstevel@tonic-gate if (conn->conn_call == NULL) { 1093*0Sstevel@tonic-gate free((char *)conn); 1094*0Sstevel@tonic-gate nfslib_log_tli_error("t_alloc", fd, nconf); 1095*0Sstevel@tonic-gate return (FALSE); 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate if (t_listen(fd, conn->conn_call) == -1) { 1099*0Sstevel@tonic-gate nfslib_log_tli_error("t_listen", fd, nconf); 1100*0Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL); 1101*0Sstevel@tonic-gate free((char *)conn); 1102*0Sstevel@tonic-gate return (FALSE); 1103*0Sstevel@tonic-gate } 1104*0Sstevel@tonic-gate 1105*0Sstevel@tonic-gate if (conn->conn_call->udata.len > 0) { 1106*0Sstevel@tonic-gate syslog(LOG_WARNING, 1107*0Sstevel@tonic-gate "rejecting inbound connection(%s) with %d bytes of connect data", 1108*0Sstevel@tonic-gate nconf->nc_proto, conn->conn_call->udata.len); 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate conn->conn_call->udata.len = 0; 1111*0Sstevel@tonic-gate (void) t_snddis(fd, conn->conn_call); 1112*0Sstevel@tonic-gate (void) t_free((char *)conn->conn_call, T_CALL); 1113*0Sstevel@tonic-gate free((char *)conn); 1114*0Sstevel@tonic-gate return (FALSE); 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate if ((next_conn = *connp) != NULL) { 1118*0Sstevel@tonic-gate next_conn->conn_prev->conn_next = conn; 1119*0Sstevel@tonic-gate conn->conn_next = next_conn; 1120*0Sstevel@tonic-gate conn->conn_prev = next_conn->conn_prev; 1121*0Sstevel@tonic-gate next_conn->conn_prev = conn; 1122*0Sstevel@tonic-gate } else { 1123*0Sstevel@tonic-gate conn->conn_next = conn; 1124*0Sstevel@tonic-gate conn->conn_prev = conn; 1125*0Sstevel@tonic-gate *connp = conn; 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate return (TRUE); 1128*0Sstevel@tonic-gate } 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate static int 1131*0Sstevel@tonic-gate discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp) 1132*0Sstevel@tonic-gate { 1133*0Sstevel@tonic-gate struct conn_ind *conn; 1134*0Sstevel@tonic-gate struct t_discon discon; 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate discon.udata.buf = (char *)0; 1137*0Sstevel@tonic-gate discon.udata.maxlen = 0; 1138*0Sstevel@tonic-gate if (t_rcvdis(fd, &discon) == -1) { 1139*0Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf); 1140*0Sstevel@tonic-gate return (-1); 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate conn = *connp; 1144*0Sstevel@tonic-gate if (conn == NULL) 1145*0Sstevel@tonic-gate return (0); 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate do { 1148*0Sstevel@tonic-gate if (conn->conn_call->sequence == discon.sequence) { 1149*0Sstevel@tonic-gate if (conn->conn_next == conn) 1150*0Sstevel@tonic-gate *connp = (struct conn_ind *)0; 1151*0Sstevel@tonic-gate else { 1152*0Sstevel@tonic-gate if (conn == *connp) { 1153*0Sstevel@tonic-gate *connp = conn->conn_next; 1154*0Sstevel@tonic-gate } 1155*0Sstevel@tonic-gate conn->conn_next->conn_prev = conn->conn_prev; 1156*0Sstevel@tonic-gate conn->conn_prev->conn_next = conn->conn_next; 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate free((char *)conn); 1159*0Sstevel@tonic-gate break; 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate conn = conn->conn_next; 1162*0Sstevel@tonic-gate } while (conn != *connp); 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate return (0); 1165*0Sstevel@tonic-gate } 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate static void 1168*0Sstevel@tonic-gate cots_listen_event(int fd, int conn_index) 1169*0Sstevel@tonic-gate { 1170*0Sstevel@tonic-gate struct t_call *call; 1171*0Sstevel@tonic-gate struct conn_ind *conn; 1172*0Sstevel@tonic-gate struct conn_ind *conn_head; 1173*0Sstevel@tonic-gate int event; 1174*0Sstevel@tonic-gate struct netconfig *nconf = &conn_polled[conn_index].nc; 1175*0Sstevel@tonic-gate int new_fd; 1176*0Sstevel@tonic-gate struct netbuf addrmask; 1177*0Sstevel@tonic-gate int ret = 0; 1178*0Sstevel@tonic-gate char *clnt; 1179*0Sstevel@tonic-gate char *clnt_uaddr = NULL; 1180*0Sstevel@tonic-gate struct nd_hostservlist *clnt_serv = NULL; 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate conn_head = (struct conn_ind *)0; 1183*0Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head); 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate while ((conn = conn_head) != NULL) { 1186*0Sstevel@tonic-gate conn_head = conn->conn_next; 1187*0Sstevel@tonic-gate if (conn_head == conn) 1188*0Sstevel@tonic-gate conn_head = (struct conn_ind *)0; 1189*0Sstevel@tonic-gate else { 1190*0Sstevel@tonic-gate conn_head->conn_prev = conn->conn_prev; 1191*0Sstevel@tonic-gate conn->conn_prev->conn_next = conn_head; 1192*0Sstevel@tonic-gate } 1193*0Sstevel@tonic-gate call = conn->conn_call; 1194*0Sstevel@tonic-gate free((char *)conn); 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate /* 1197*0Sstevel@tonic-gate * If we have already accepted the maximum number of 1198*0Sstevel@tonic-gate * connections allowed on the command line, then drop 1199*0Sstevel@tonic-gate * the oldest connection (for any protocol) before 1200*0Sstevel@tonic-gate * accepting the new connection. Unless explicitly 1201*0Sstevel@tonic-gate * set on the command line, max_conns_allowed is -1. 1202*0Sstevel@tonic-gate */ 1203*0Sstevel@tonic-gate if (max_conns_allowed != -1 && num_conns >= max_conns_allowed) 1204*0Sstevel@tonic-gate conn_close_oldest(); 1205*0Sstevel@tonic-gate 1206*0Sstevel@tonic-gate /* 1207*0Sstevel@tonic-gate * Create a new transport endpoint for the same proto as 1208*0Sstevel@tonic-gate * the listener. 1209*0Sstevel@tonic-gate */ 1210*0Sstevel@tonic-gate new_fd = nfslib_transport_open(nconf); 1211*0Sstevel@tonic-gate if (new_fd == -1) { 1212*0Sstevel@tonic-gate call->udata.len = 0; 1213*0Sstevel@tonic-gate (void) t_snddis(fd, call); 1214*0Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 1215*0Sstevel@tonic-gate syslog(LOG_ERR, "Cannot establish transport over %s", 1216*0Sstevel@tonic-gate nconf->nc_device); 1217*0Sstevel@tonic-gate continue; 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate /* Bind to a generic address/port for the accepting stream. */ 1221*0Sstevel@tonic-gate if (t_bind(new_fd, (struct t_bind *)NULL, 1222*0Sstevel@tonic-gate (struct t_bind *)NULL) == -1) { 1223*0Sstevel@tonic-gate nfslib_log_tli_error("t_bind", new_fd, nconf); 1224*0Sstevel@tonic-gate call->udata.len = 0; 1225*0Sstevel@tonic-gate (void) t_snddis(fd, call); 1226*0Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 1227*0Sstevel@tonic-gate (void) t_close(new_fd); 1228*0Sstevel@tonic-gate continue; 1229*0Sstevel@tonic-gate } 1230*0Sstevel@tonic-gate 1231*0Sstevel@tonic-gate while (t_accept(fd, new_fd, call) == -1) { 1232*0Sstevel@tonic-gate if (t_errno != TLOOK) { 1233*0Sstevel@tonic-gate #ifdef DEBUG 1234*0Sstevel@tonic-gate nfslib_log_tli_error("t_accept", fd, nconf); 1235*0Sstevel@tonic-gate #endif 1236*0Sstevel@tonic-gate call->udata.len = 0; 1237*0Sstevel@tonic-gate (void) t_snddis(fd, call); 1238*0Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 1239*0Sstevel@tonic-gate (void) t_close(new_fd); 1240*0Sstevel@tonic-gate goto do_next_conn; 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate while (event = t_look(fd)) { 1243*0Sstevel@tonic-gate switch (event) { 1244*0Sstevel@tonic-gate case T_LISTEN: 1245*0Sstevel@tonic-gate #ifdef DEBUG 1246*0Sstevel@tonic-gate printf( 1247*0Sstevel@tonic-gate "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto); 1248*0Sstevel@tonic-gate #endif 1249*0Sstevel@tonic-gate (void) conn_get(fd, nconf, &conn_head); 1250*0Sstevel@tonic-gate continue; 1251*0Sstevel@tonic-gate case T_DISCONNECT: 1252*0Sstevel@tonic-gate #ifdef DEBUG 1253*0Sstevel@tonic-gate printf( 1254*0Sstevel@tonic-gate "cots_listen_event(%s): T_DISCONNECT during accept processing\n", 1255*0Sstevel@tonic-gate nconf->nc_proto); 1256*0Sstevel@tonic-gate #endif 1257*0Sstevel@tonic-gate (void) discon_get(fd, nconf, 1258*0Sstevel@tonic-gate &conn_head); 1259*0Sstevel@tonic-gate continue; 1260*0Sstevel@tonic-gate default: 1261*0Sstevel@tonic-gate syslog(LOG_ERR, 1262*0Sstevel@tonic-gate "unexpected event 0x%x during accept processing (%s)", 1263*0Sstevel@tonic-gate event, nconf->nc_proto); 1264*0Sstevel@tonic-gate call->udata.len = 0; 1265*0Sstevel@tonic-gate (void) t_snddis(fd, call); 1266*0Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 1267*0Sstevel@tonic-gate (void) t_close(new_fd); 1268*0Sstevel@tonic-gate goto do_next_conn; 1269*0Sstevel@tonic-gate } 1270*0Sstevel@tonic-gate } 1271*0Sstevel@tonic-gate } 1272*0Sstevel@tonic-gate 1273*0Sstevel@tonic-gate if (set_addrmask(new_fd, nconf, &addrmask) < 0) { 1274*0Sstevel@tonic-gate (void) syslog(LOG_ERR, 1275*0Sstevel@tonic-gate "Cannot set address mask for %s", 1276*0Sstevel@tonic-gate nconf->nc_netid); 1277*0Sstevel@tonic-gate return; 1278*0Sstevel@tonic-gate } 1279*0Sstevel@tonic-gate 1280*0Sstevel@tonic-gate /* Tell KRPC about the new stream. */ 1281*0Sstevel@tonic-gate if (Mysvc4 != NULL) 1282*0Sstevel@tonic-gate ret = (*Mysvc4)(new_fd, &addrmask, nconf, 1283*0Sstevel@tonic-gate NFS4_KRPC_START, &call->addr); 1284*0Sstevel@tonic-gate else 1285*0Sstevel@tonic-gate ret = (*Mysvc)(new_fd, addrmask, nconf); 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate if (ret < 0) { 1288*0Sstevel@tonic-gate if (errno != ENOTCONN) { 1289*0Sstevel@tonic-gate syslog(LOG_ERR, 1290*0Sstevel@tonic-gate "unable to register new connection: %m"); 1291*0Sstevel@tonic-gate } else { 1292*0Sstevel@tonic-gate /* 1293*0Sstevel@tonic-gate * This is the only error that could be 1294*0Sstevel@tonic-gate * caused by the client, so who was it? 1295*0Sstevel@tonic-gate */ 1296*0Sstevel@tonic-gate if (netdir_getbyaddr(nconf, &clnt_serv, 1297*0Sstevel@tonic-gate &(call->addr)) == ND_OK && 1298*0Sstevel@tonic-gate clnt_serv->h_cnt > 0) 1299*0Sstevel@tonic-gate clnt = clnt_serv->h_hostservs->h_host; 1300*0Sstevel@tonic-gate else 1301*0Sstevel@tonic-gate clnt = clnt_uaddr = taddr2uaddr(nconf, 1302*0Sstevel@tonic-gate &(call->addr)); 1303*0Sstevel@tonic-gate /* 1304*0Sstevel@tonic-gate * If we don't know who the client was, 1305*0Sstevel@tonic-gate * remain silent. 1306*0Sstevel@tonic-gate */ 1307*0Sstevel@tonic-gate if (clnt) 1308*0Sstevel@tonic-gate syslog(LOG_ERR, 1309*0Sstevel@tonic-gate "unable to register new connection: client %s has dropped connection", clnt); 1310*0Sstevel@tonic-gate if (clnt_serv) 1311*0Sstevel@tonic-gate netdir_free(clnt_serv, ND_HOSTSERVLIST); 1312*0Sstevel@tonic-gate if (clnt_uaddr) 1313*0Sstevel@tonic-gate free(clnt_uaddr); 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate free(addrmask.buf); 1316*0Sstevel@tonic-gate (void) t_snddis(new_fd, (struct t_call *)0); 1317*0Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 1318*0Sstevel@tonic-gate (void) t_close(new_fd); 1319*0Sstevel@tonic-gate goto do_next_conn; 1320*0Sstevel@tonic-gate } 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gate free(addrmask.buf); 1323*0Sstevel@tonic-gate (void) t_free((char *)call, T_CALL); 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate /* 1326*0Sstevel@tonic-gate * Poll on the new descriptor so that we get disconnect 1327*0Sstevel@tonic-gate * and orderly release indications. 1328*0Sstevel@tonic-gate */ 1329*0Sstevel@tonic-gate num_conns++; 1330*0Sstevel@tonic-gate add_to_poll_list(new_fd, nconf); 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate /* Reset nconf in case it has been moved. */ 1333*0Sstevel@tonic-gate nconf = &conn_polled[conn_index].nc; 1334*0Sstevel@tonic-gate do_next_conn:; 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate } 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate static int 1339*0Sstevel@tonic-gate do_poll_cots_action(int fd, int conn_index) 1340*0Sstevel@tonic-gate { 1341*0Sstevel@tonic-gate char buf[256]; 1342*0Sstevel@tonic-gate int event; 1343*0Sstevel@tonic-gate int i1; 1344*0Sstevel@tonic-gate int flags; 1345*0Sstevel@tonic-gate struct conn_entry *connent = &conn_polled[conn_index]; 1346*0Sstevel@tonic-gate struct netconfig *nconf = &(connent->nc); 1347*0Sstevel@tonic-gate const char *errorstr; 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate while (event = t_look(fd)) { 1350*0Sstevel@tonic-gate switch (event) { 1351*0Sstevel@tonic-gate case T_LISTEN: 1352*0Sstevel@tonic-gate #ifdef DEBUG 1353*0Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd); 1354*0Sstevel@tonic-gate #endif 1355*0Sstevel@tonic-gate cots_listen_event(fd, conn_index); 1356*0Sstevel@tonic-gate break; 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate case T_DATA: 1359*0Sstevel@tonic-gate #ifdef DEBUG 1360*0Sstevel@tonic-gate printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto); 1361*0Sstevel@tonic-gate #endif 1362*0Sstevel@tonic-gate /* 1363*0Sstevel@tonic-gate * Receive a private notification from CONS rpcmod. 1364*0Sstevel@tonic-gate */ 1365*0Sstevel@tonic-gate i1 = t_rcv(fd, buf, sizeof (buf), &flags); 1366*0Sstevel@tonic-gate if (i1 == -1) { 1367*0Sstevel@tonic-gate syslog(LOG_ERR, "t_rcv failed"); 1368*0Sstevel@tonic-gate break; 1369*0Sstevel@tonic-gate } 1370*0Sstevel@tonic-gate if (i1 < sizeof (int)) 1371*0Sstevel@tonic-gate break; 1372*0Sstevel@tonic-gate i1 = BE32_TO_U32(buf); 1373*0Sstevel@tonic-gate if (i1 == 1 || i1 == 2) { 1374*0Sstevel@tonic-gate /* 1375*0Sstevel@tonic-gate * This connection has been idle for too long, 1376*0Sstevel@tonic-gate * so release it as politely as we can. If we 1377*0Sstevel@tonic-gate * have already initiated an orderly release 1378*0Sstevel@tonic-gate * and we get notified that the stream is 1379*0Sstevel@tonic-gate * still idle, pull the plug. This prevents 1380*0Sstevel@tonic-gate * hung connections from continuing to consume 1381*0Sstevel@tonic-gate * resources. 1382*0Sstevel@tonic-gate */ 1383*0Sstevel@tonic-gate #ifdef DEBUG 1384*0Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd); 1385*0Sstevel@tonic-gate printf("initiating orderly release of idle connection\n"); 1386*0Sstevel@tonic-gate #endif 1387*0Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_COTS || 1388*0Sstevel@tonic-gate connent->closing != 0) { 1389*0Sstevel@tonic-gate (void) t_snddis(fd, (struct t_call *)0); 1390*0Sstevel@tonic-gate goto fdclose; 1391*0Sstevel@tonic-gate } 1392*0Sstevel@tonic-gate /* 1393*0Sstevel@tonic-gate * For NC_TPI_COTS_ORD, the stream is closed 1394*0Sstevel@tonic-gate * and removed from the poll list when the 1395*0Sstevel@tonic-gate * T_ORDREL is received from the provider. We 1396*0Sstevel@tonic-gate * don't wait for it here because it may take 1397*0Sstevel@tonic-gate * a while for the transport to shut down. 1398*0Sstevel@tonic-gate */ 1399*0Sstevel@tonic-gate if (t_sndrel(fd) == -1) { 1400*0Sstevel@tonic-gate syslog(LOG_ERR, 1401*0Sstevel@tonic-gate "unable to send orderly release %m"); 1402*0Sstevel@tonic-gate } 1403*0Sstevel@tonic-gate connent->closing = 1; 1404*0Sstevel@tonic-gate } else 1405*0Sstevel@tonic-gate syslog(LOG_ERR, 1406*0Sstevel@tonic-gate "unexpected event from CONS rpcmod %d", i1); 1407*0Sstevel@tonic-gate break; 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate case T_ORDREL: 1410*0Sstevel@tonic-gate #ifdef DEBUG 1411*0Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd); 1412*0Sstevel@tonic-gate #endif 1413*0Sstevel@tonic-gate /* Perform an orderly release. */ 1414*0Sstevel@tonic-gate if (t_rcvrel(fd) == 0) { 1415*0Sstevel@tonic-gate /* T_ORDREL on listen fd's should be ignored */ 1416*0Sstevel@tonic-gate if (!is_listen_fd_index(conn_index)) { 1417*0Sstevel@tonic-gate (void) t_sndrel(fd); 1418*0Sstevel@tonic-gate goto fdclose; 1419*0Sstevel@tonic-gate } 1420*0Sstevel@tonic-gate break; 1421*0Sstevel@tonic-gate 1422*0Sstevel@tonic-gate } else if (t_errno == TLOOK) { 1423*0Sstevel@tonic-gate break; 1424*0Sstevel@tonic-gate } else { 1425*0Sstevel@tonic-gate nfslib_log_tli_error("t_rcvrel", fd, nconf); 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate /* 1428*0Sstevel@tonic-gate * check to make sure we do not close 1429*0Sstevel@tonic-gate * listen fd 1430*0Sstevel@tonic-gate */ 1431*0Sstevel@tonic-gate if (is_listen_fd_index(conn_index)) 1432*0Sstevel@tonic-gate break; 1433*0Sstevel@tonic-gate else 1434*0Sstevel@tonic-gate goto fdclose; 1435*0Sstevel@tonic-gate } 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gate case T_DISCONNECT: 1438*0Sstevel@tonic-gate #ifdef DEBUG 1439*0Sstevel@tonic-gate printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd); 1440*0Sstevel@tonic-gate #endif 1441*0Sstevel@tonic-gate if (t_rcvdis(fd, (struct t_discon *)NULL) == -1) 1442*0Sstevel@tonic-gate nfslib_log_tli_error("t_rcvdis", fd, nconf); 1443*0Sstevel@tonic-gate 1444*0Sstevel@tonic-gate /* 1445*0Sstevel@tonic-gate * T_DISCONNECT on listen fd's should be ignored. 1446*0Sstevel@tonic-gate */ 1447*0Sstevel@tonic-gate if (is_listen_fd_index(conn_index)) 1448*0Sstevel@tonic-gate break; 1449*0Sstevel@tonic-gate else 1450*0Sstevel@tonic-gate goto fdclose; 1451*0Sstevel@tonic-gate 1452*0Sstevel@tonic-gate case T_ERROR: 1453*0Sstevel@tonic-gate default: 1454*0Sstevel@tonic-gate if (event == T_ERROR || t_errno == TSYSERR) { 1455*0Sstevel@tonic-gate if ((errorstr = strerror(errno)) == NULL) { 1456*0Sstevel@tonic-gate (void) sprintf(buf, "Unknown error num %d", 1457*0Sstevel@tonic-gate errno); 1458*0Sstevel@tonic-gate errorstr = (const char *) buf; 1459*0Sstevel@tonic-gate } 1460*0Sstevel@tonic-gate } else if (event == -1) 1461*0Sstevel@tonic-gate errorstr = t_strerror(t_errno); 1462*0Sstevel@tonic-gate else 1463*0Sstevel@tonic-gate errorstr = ""; 1464*0Sstevel@tonic-gate syslog(LOG_ERR, 1465*0Sstevel@tonic-gate "unexpected TLI event (0x%x) on " 1466*0Sstevel@tonic-gate "connection-oriented transport(%s,%d):%s", 1467*0Sstevel@tonic-gate event, nconf->nc_proto, fd, errorstr); 1468*0Sstevel@tonic-gate fdclose: 1469*0Sstevel@tonic-gate num_conns--; 1470*0Sstevel@tonic-gate remove_from_poll_list(fd); 1471*0Sstevel@tonic-gate (void) t_close(fd); 1472*0Sstevel@tonic-gate return (0); 1473*0Sstevel@tonic-gate } 1474*0Sstevel@tonic-gate } 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate return (0); 1477*0Sstevel@tonic-gate } 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate static char * 1480*0Sstevel@tonic-gate serv_name_to_port_name(char *name) 1481*0Sstevel@tonic-gate { 1482*0Sstevel@tonic-gate /* 1483*0Sstevel@tonic-gate * Map service names (used primarily in logging) to 1484*0Sstevel@tonic-gate * RPC port names (used by netdir_*() routines). 1485*0Sstevel@tonic-gate */ 1486*0Sstevel@tonic-gate if (strcmp(name, "NFS") == 0) { 1487*0Sstevel@tonic-gate return ("nfs"); 1488*0Sstevel@tonic-gate } else if (strcmp(name, "NLM") == 0) { 1489*0Sstevel@tonic-gate return ("lockd"); 1490*0Sstevel@tonic-gate } else if (strcmp(name, "NFS4_CALLBACK") == 0) { 1491*0Sstevel@tonic-gate return ("nfs4_callback"); 1492*0Sstevel@tonic-gate } 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate return ("unrecognized"); 1495*0Sstevel@tonic-gate } 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate static int 1498*0Sstevel@tonic-gate bind_to_provider(char *provider, char *serv, struct netbuf **addr, 1499*0Sstevel@tonic-gate struct netconfig **retnconf) 1500*0Sstevel@tonic-gate { 1501*0Sstevel@tonic-gate struct netconfig *nconf; 1502*0Sstevel@tonic-gate NCONF_HANDLE *nc; 1503*0Sstevel@tonic-gate struct nd_hostserv hs; 1504*0Sstevel@tonic-gate 1505*0Sstevel@tonic-gate hs.h_host = HOST_SELF; 1506*0Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv); 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 1509*0Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 1510*0Sstevel@tonic-gate return (-1); 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 1513*0Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) && 1514*0Sstevel@tonic-gate strcmp(nconf->nc_device, provider) == 0) { 1515*0Sstevel@tonic-gate *retnconf = nconf; 1516*0Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs, 1517*0Sstevel@tonic-gate listen_backlog)); 1518*0Sstevel@tonic-gate } 1519*0Sstevel@tonic-gate } 1520*0Sstevel@tonic-gate (void) endnetconfig(nc); 1521*0Sstevel@tonic-gate 1522*0Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for provider %s", 1523*0Sstevel@tonic-gate provider); 1524*0Sstevel@tonic-gate return (-1); 1525*0Sstevel@tonic-gate } 1526*0Sstevel@tonic-gate 1527*0Sstevel@tonic-gate static int 1528*0Sstevel@tonic-gate bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr, 1529*0Sstevel@tonic-gate struct netconfig **retnconf) 1530*0Sstevel@tonic-gate { 1531*0Sstevel@tonic-gate struct netconfig *nconf; 1532*0Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 1533*0Sstevel@tonic-gate struct nd_hostserv hs; 1534*0Sstevel@tonic-gate 1535*0Sstevel@tonic-gate hs.h_host = HOST_SELF; 1536*0Sstevel@tonic-gate hs.h_serv = serv_name_to_port_name(serv); 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) { 1539*0Sstevel@tonic-gate syslog(LOG_ERR, "setnetconfig failed: %m"); 1540*0Sstevel@tonic-gate return (-1); 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 1543*0Sstevel@tonic-gate if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) { 1544*0Sstevel@tonic-gate *retnconf = nconf; 1545*0Sstevel@tonic-gate return (nfslib_bindit(nconf, addr, &hs, 1546*0Sstevel@tonic-gate listen_backlog)); 1547*0Sstevel@tonic-gate } 1548*0Sstevel@tonic-gate } 1549*0Sstevel@tonic-gate (void) endnetconfig(nc); 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s", 1552*0Sstevel@tonic-gate proto); 1553*0Sstevel@tonic-gate return (-1); 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate #include <netinet/in.h> 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate /* 1559*0Sstevel@tonic-gate * Create an address mask appropriate for the transport. 1560*0Sstevel@tonic-gate * The mask is used to obtain the host-specific part of 1561*0Sstevel@tonic-gate * a network address when comparing addresses. 1562*0Sstevel@tonic-gate * For an internet address the host-specific part is just 1563*0Sstevel@tonic-gate * the 32 bit IP address and this part of the mask is set 1564*0Sstevel@tonic-gate * to all-ones. The port number part of the mask is zeroes. 1565*0Sstevel@tonic-gate */ 1566*0Sstevel@tonic-gate static int 1567*0Sstevel@tonic-gate set_addrmask(fd, nconf, mask) 1568*0Sstevel@tonic-gate struct netconfig *nconf; 1569*0Sstevel@tonic-gate struct netbuf *mask; 1570*0Sstevel@tonic-gate { 1571*0Sstevel@tonic-gate struct t_info info; 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate /* 1574*0Sstevel@tonic-gate * Find the size of the address we need to mask. 1575*0Sstevel@tonic-gate */ 1576*0Sstevel@tonic-gate if (t_getinfo(fd, &info) < 0) { 1577*0Sstevel@tonic-gate t_error("t_getinfo"); 1578*0Sstevel@tonic-gate return (-1); 1579*0Sstevel@tonic-gate } 1580*0Sstevel@tonic-gate mask->len = mask->maxlen = info.addr; 1581*0Sstevel@tonic-gate if (info.addr <= 0) { 1582*0Sstevel@tonic-gate syslog(LOG_ERR, "set_addrmask: address size: %ld", 1583*0Sstevel@tonic-gate info.addr); 1584*0Sstevel@tonic-gate return (-1); 1585*0Sstevel@tonic-gate } 1586*0Sstevel@tonic-gate 1587*0Sstevel@tonic-gate mask->buf = (char *)malloc(mask->len); 1588*0Sstevel@tonic-gate if (mask->buf == NULL) { 1589*0Sstevel@tonic-gate syslog(LOG_ERR, "set_addrmask: no memory"); 1590*0Sstevel@tonic-gate return (-1); 1591*0Sstevel@tonic-gate } 1592*0Sstevel@tonic-gate (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */ 1593*0Sstevel@tonic-gate 1594*0Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 1595*0Sstevel@tonic-gate /* 1596*0Sstevel@tonic-gate * Set the mask so that the port is ignored. 1597*0Sstevel@tonic-gate */ 1598*0Sstevel@tonic-gate /* LINTED pointer alignment */ 1599*0Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr = 1600*0Sstevel@tonic-gate (ulong_t)~0; 1601*0Sstevel@tonic-gate /* LINTED pointer alignment */ 1602*0Sstevel@tonic-gate ((struct sockaddr_in *)mask->buf)->sin_family = 1603*0Sstevel@tonic-gate (ushort_t)~0; 1604*0Sstevel@tonic-gate } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) { 1605*0Sstevel@tonic-gate /* LINTED pointer alignment */ 1606*0Sstevel@tonic-gate (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr, 1607*0Sstevel@tonic-gate (uchar_t)~0, sizeof (struct in6_addr)); 1608*0Sstevel@tonic-gate /* LINTED pointer alignment */ 1609*0Sstevel@tonic-gate ((struct sockaddr_in6 *)mask->buf)->sin6_family = 1610*0Sstevel@tonic-gate (ushort_t)~0; 1611*0Sstevel@tonic-gate } else { 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate /* 1614*0Sstevel@tonic-gate * Set all mask bits. 1615*0Sstevel@tonic-gate */ 1616*0Sstevel@tonic-gate (void) memset(mask->buf, 0xFF, mask->len); 1617*0Sstevel@tonic-gate } 1618*0Sstevel@tonic-gate return (0); 1619*0Sstevel@tonic-gate } 1620*0Sstevel@tonic-gate 1621*0Sstevel@tonic-gate /* 1622*0Sstevel@tonic-gate * For listen fd's index is always less than end_listen_fds. 1623*0Sstevel@tonic-gate * end_listen_fds is defined externally in the daemon that uses this library. 1624*0Sstevel@tonic-gate * It's value is equal to the number of open file descriptors after the 1625*0Sstevel@tonic-gate * last listen end point was opened but before any connection was accepted. 1626*0Sstevel@tonic-gate */ 1627*0Sstevel@tonic-gate static int 1628*0Sstevel@tonic-gate is_listen_fd_index(int index) 1629*0Sstevel@tonic-gate { 1630*0Sstevel@tonic-gate return (index < end_listen_fds); 1631*0Sstevel@tonic-gate } 1632