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