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 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /*
  27  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  28  */
  29 
  30 /*
  31  * Network SNDR/ncall-ip server - based on nfsd
  32  */
  33 #include <sys/types.h>
  34 #include <rpc/types.h>
  35 #include <errno.h>
  36 #include <netdb.h>
  37 #include <sys/socket.h>
  38 #include <netconfig.h>
  39 #include <stropts.h>
  40 #include <fcntl.h>
  41 #include <stdio.h>
  42 #include <strings.h>
  43 #include <signal.h>
  44 #include <unistd.h>
  45 #include <stdlib.h>
  46 #include <netdir.h>
  47 #include <rpc/rpc_com.h>
  48 #include <rpc/rpc.h>
  49 #include <tiuser.h>
  50 #include <netinet/tcp.h>
  51 #include <netinet/in.h>
  52 #include <syslog.h>
  53 #include <locale.h>
  54 #include <langinfo.h>
  55 #include <libintl.h>
  56 #include <libgen.h>
  57 #include <deflt.h>
  58 #include <sys/resource.h>
  59 
  60 #include <sys/nsctl/nsctl.h>
  61 
  62 #ifdef  __NCALL__
  63 
  64 #include <sys/ncall/ncall.h>
  65 #include <sys/ncall/ncall_ip.h>
  66 #include <sys/nsctl/libncall.h>
  67 
  68 #define RDC_POOL_CREATE NC_IOC_POOL_CREATE
  69 #define RDC_POOL_RUN    NC_IOC_POOL_RUN
  70 #define RDC_POOL_WAIT   NC_IOC_POOL_WAIT
  71 #define RDC_PROGRAM     NCALL_PROGRAM
  72 #define RDC_SERVICE     "ncall"
  73 #undef RDC_SVCPOOL_ID   /* We are overloading this value */
  74 #define RDC_SVCPOOL_ID  NCALL_SVCPOOL_ID
  75 #define RDC_SVC_NAME    "NCALL"
  76 #define RDC_VERS_MIN    NCALL_VERS_MIN
  77 #define RDC_VERS_MAX    NCALL_VERS_MAX
  78 
  79 #else   /* !__NCALL__ */
  80 
  81 #include <sys/nsctl/rdc_ioctl.h>
  82 #include <sys/nsctl/rdc_io.h>
  83 #include <sys/nsctl/librdc.h>
  84 
  85 #define RDC_SERVICE     "rdc"
  86 #define RDC_SVC_NAME    "RDC"
  87 
  88 #endif  /* __NCALL__ */
  89 
  90 #define RDCADMIN        "/etc/default/sndr"
  91 
  92 #include <nsctl.h>
  93 
  94 struct conn_ind {
  95         struct conn_ind *conn_next;
  96         struct conn_ind *conn_prev;
  97         struct t_call   *conn_call;
  98 };
  99 
 100 struct conn_entry {
 101         bool_t                  closing;
 102         struct netconfig        nc;
 103 };
 104 
 105 static char *progname;
 106 static struct conn_entry *conn_polled;
 107 static int num_conns;                   /* Current number of connections */
 108 static struct pollfd *poll_array;       /* array of poll descriptors for poll */
 109 static size_t num_fds = 0;              /* number of transport fds opened */
 110 static void poll_for_action();
 111 static void remove_from_poll_list(int);
 112 static int do_poll_cots_action(int, int);
 113 static int do_poll_clts_action(int, int);
 114 static void add_to_poll_list(int, struct netconfig *);
 115 static int bind_to_provider(char *, char *, struct netbuf **,
 116     struct netconfig **);
 117 static int set_addrmask(int, struct netconfig *, struct netbuf *);
 118 static void conn_close_oldest(void);
 119 static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
 120 static void cots_listen_event(int, int);
 121 static int discon_get(int, struct netconfig *, struct conn_ind **);
 122 static int nofile_increase(int);
 123 static int is_listen_fd_index(int);
 124 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
 125 static int sndrsvcpool(int);
 126 static int svcwait(int id);
 127 #endif
 128 
 129 
 130 /*
 131  * RPC protocol block.  Useful for passing registration information.
 132  */
 133 struct protob {
 134         char *serv;             /* ASCII service name, e.g. "RDC" */
 135         int versmin;            /* minimum version no. to be registered */
 136         int versmax;            /* maximum version no. to be registered */
 137         int program;            /* program no. to be registered */
 138         struct protob *next;    /* next entry on list */
 139 };
 140 
 141 
 142 
 143 static size_t end_listen_fds;
 144 static int debugflg = 0;
 145 static int max_conns_allowed = -1;
 146 static int listen_backlog = 10;
 147 static char *trans_provider = (char *)NULL;
 148 static int rdcsvc(int, struct netbuf, struct netconfig *);
 149 
 150 /* used by cots_listen_event() */
 151 static int (*Mysvc)(int, struct netbuf, struct netconfig *) = rdcsvc;
 152 
 153 /*
 154  * Determine valid semantics for rdc.
 155  */
 156 #define OK_TPI_TYPE(_nconf)     \
 157         (_nconf->nc_semantics == NC_TPI_CLTS || \
 158         _nconf->nc_semantics == NC_TPI_COTS || \
 159         _nconf->nc_semantics == NC_TPI_COTS_ORD)
 160 
 161 #define BE32_TO_U32(a)          \
 162         ((((uint32_t)((uchar_t *)a)[0] & 0xFF) << (uint32_t)24) |\
 163         (((uint32_t)((uchar_t *)a)[1] & 0xFF) << (uint32_t)16) |\
 164         (((uint32_t)((uchar_t *)a)[2] & 0xFF) << (uint32_t)8)  |\
 165         ((uint32_t)((uchar_t *)a)[3] & 0xFF))
 166 
 167 #ifdef DEBUG
 168 /*
 169  * Only support UDP in DEBUG mode for now
 170  */
 171 static  char *defaultproviders[] = { "/dev/tcp", "/dev/tcp6", "/dev/udp",
 172                 "/dev/udp6", NULL };
 173 #else
 174 static  char *defaultproviders[] = { "/dev/tcp6", "/dev/tcp", NULL };
 175 #endif
 176 
 177 /*
 178  * Number of elements to add to the poll array on each allocation.
 179  */
 180 #define POLL_ARRAY_INC_SIZE     64
 181 #define NOFILE_INC_SIZE         64
 182 
 183 #ifdef  __NCALL__
 184 const char *rdc_devr = "/dev/ncallip";
 185 #else
 186 const char *rdc_devr = "/dev/rdc";
 187 #endif
 188 
 189 static int rdc_fdr;
 190 static int
 191 
 192 open_rdc(void)
 193 {
 194         int fd = open(rdc_devr, O_RDONLY);
 195 
 196         if (fd < 0)
 197                 return (-1);
 198 
 199         return (rdc_fdr = fd);
 200 }
 201 
 202 static int
 203 sndrsys(int type, void *arg)
 204 {
 205         int ret = -1;
 206         if (!rdc_fdr && open_rdc() < 0) { /* open failed */
 207                 syslog(LOG_ERR, "open_rdc() failed: %m\n");
 208         } else {
 209                 if ((ret = ioctl(rdc_fdr, type, arg)) < 0) {
 210                         syslog(LOG_ERR, "ioctl(rdc_ioctl) failed: %m\n");
 211                 }
 212         }
 213         return (ret);
 214 }
 215 
 216 int
 217 rdc_transport_open(struct netconfig *nconf)
 218 {
 219         int fd;
 220         struct strioctl strioc;
 221 
 222         if ((nconf == (struct netconfig *)NULL) ||
 223             (nconf->nc_device == (char *)NULL)) {
 224                 syslog(LOG_ERR, "No netconfig device");
 225                 return (-1);
 226         }
 227 
 228         /*
 229          * Open the transport device.
 230          */
 231         fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
 232         if (fd == -1)  {
 233                 if (t_errno == TSYSERR && errno == EMFILE &&
 234                     (nofile_increase(0) == 0)) {
 235                         /* Try again with a higher NOFILE limit. */
 236                         fd = t_open(nconf->nc_device, O_RDWR, NULL);
 237                 }
 238                 if (fd == -1) {
 239                         if (t_errno == TSYSERR) {
 240                                 syslog(LOG_ERR, "t_open failed: %m");
 241                         } else {
 242                                 syslog(LOG_ERR, "t_open failed: %s",
 243                                     t_errlist[t_errno]);
 244                         }
 245                         return (-1);
 246                 }
 247         }
 248 
 249         /*
 250          * Pop timod because the RPC module must be as close as possible
 251          * to the transport.
 252          */
 253         if (ioctl(fd, I_POP, 0) < 0) {
 254                 syslog(LOG_ERR, "I_POP of timod failed: %m");
 255                 if (t_close(fd) == -1) {
 256                         if (t_errno == TSYSERR) {
 257                                 syslog(LOG_ERR, "t_close failed on %d: %m", fd);
 258                         } else {
 259                                 syslog(LOG_ERR, "t_close failed on %d: %s",
 260                                     fd, t_errlist[t_errno]);
 261                         }
 262                 }
 263                 return (-1);
 264         }
 265 
 266         if (nconf->nc_semantics == NC_TPI_CLTS) {
 267                 /*
 268                  * Push rpcmod to filter data traffic to KRPC.
 269                  */
 270                 if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
 271                         syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
 272                         (void) t_close(fd);
 273                         return (-1);
 274                 }
 275         } else {
 276                 if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
 277                         syslog(LOG_ERR, "I_PUSH of CONS rpcmod failed: %m");
 278                         if (t_close(fd) == -1) {
 279                                 if (t_errno == TSYSERR) {
 280                                         syslog(LOG_ERR,
 281                                             "t_close failed on %d: %m", fd);
 282                                 } else {
 283                                         syslog(LOG_ERR,
 284                                             "t_close failed on %d: %s",
 285                                             fd, t_errlist[t_errno]);
 286                                 }
 287                         }
 288                         return (-1);
 289                 }
 290 
 291                 strioc.ic_cmd = RPC_SERVER;
 292                 strioc.ic_dp = (char *)0;
 293                 strioc.ic_len = 0;
 294                 strioc.ic_timout = -1;
 295                 /* Tell CONS rpcmod to act like a server stream. */
 296                 if (ioctl(fd, I_STR, &strioc) < 0) {
 297                         syslog(LOG_ERR, "CONS rpcmod set-up ioctl failed: %m");
 298                         if (t_close(fd) == -1) {
 299                                 if (t_errno == TSYSERR) {
 300                                         syslog(LOG_ERR,
 301                                             "t_close failed on %d: %m", fd);
 302                                 } else {
 303                                         syslog(LOG_ERR,
 304                                             "t_close failed on %d: %s",
 305                                             fd, t_errlist[t_errno]);
 306                                 }
 307                         }
 308                         return (-1);
 309                 }
 310         }
 311 
 312         /*
 313          * Re-push timod so that we will still be doing TLI
 314          * operations on the descriptor.
 315          */
 316         if (ioctl(fd, I_PUSH, "timod") < 0) {
 317                 syslog(LOG_ERR, "I_PUSH of timod failed: %m");
 318                 if (t_close(fd) == -1) {
 319                         if (t_errno == TSYSERR) {
 320                                 syslog(LOG_ERR, "t_close failed on %d: %m", fd);
 321                         } else {
 322                                 syslog(LOG_ERR, "t_close failed on %d: %s",
 323                                     fd, t_errlist[t_errno]);
 324                         }
 325                 }
 326                 return (-1);
 327         }
 328 
 329         return (fd);
 330 }
 331 
 332 
 333 void
 334 rdcd_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
 335 {
 336         int error;
 337 
 338         /*
 339          * Save the error code across syslog(), just in case syslog()
 340          * gets its own error and, therefore, overwrites errno.
 341          */
 342         error = errno;
 343         if (t_errno == TSYSERR) {
 344                 syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
 345                     tli_name, fd, nconf->nc_proto);
 346         } else {
 347                 syslog(LOG_ERR,
 348                     "%s(file descriptor %d/transport %s) TLI error %d",
 349                     tli_name, fd, nconf->nc_proto, t_errno);
 350         }
 351         errno = error;
 352 }
 353 
 354 /*
 355  * Called to set up service over a particular transport
 356  */
 357 void
 358 do_one(char *provider, char *proto, struct protob *protobp0,
 359         int (*svc)(int, struct netbuf, struct netconfig *))
 360 {
 361         struct netbuf *retaddr;
 362         struct netconfig *retnconf;
 363         struct netbuf addrmask;
 364         int vers;
 365         int sock;
 366 
 367         if (provider) {
 368                 sock = bind_to_provider(provider, protobp0->serv, &retaddr,
 369                     &retnconf);
 370         } else {
 371                 (void) syslog(LOG_ERR,
 372         "Cannot establish %s service over %s: transport setup problem.",
 373                     protobp0->serv, provider ? provider : proto);
 374                 return;
 375         }
 376 
 377         if (sock == -1) {
 378                 if ((Is_ipv6present() &&
 379                     (strcmp(provider, "/dev/tcp6") == 0)) ||
 380                     (!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
 381                         (void) syslog(LOG_ERR,
 382                             "Cannot establish %s service over %s: transport "
 383                             "setup problem.",
 384                             protobp0->serv, provider ? provider : proto);
 385                 return;
 386         }
 387 
 388         if (set_addrmask(sock, retnconf, &addrmask) < 0) {
 389                 (void) syslog(LOG_ERR,
 390                     "Cannot set address mask for %s", retnconf->nc_netid);
 391                 return;
 392         }
 393 
 394 
 395         /*
 396          * Register all versions of the programs in the protocol block list
 397          */
 398         for (vers = protobp0->versmin; vers <= protobp0->versmax; vers++) {
 399                 (void) rpcb_unset(protobp0->program, vers, retnconf);
 400                 (void) rpcb_set(protobp0->program, vers, retnconf, retaddr);
 401         }
 402 
 403         if (retnconf->nc_semantics == NC_TPI_CLTS) {
 404                 /* Don't drop core if supporting module(s) aren't loaded. */
 405                 (void) signal(SIGSYS, SIG_IGN);
 406 
 407                 /*
 408                  * svc() doesn't block, it returns success or failure.
 409                  */
 410                 if ((*svc)(sock, addrmask, retnconf) < 0) {
 411                         (void) syslog(LOG_ERR, "Cannot establish %s service "
 412                             "over <file desc. %d, protocol %s> : %m. Exiting",
 413                             protobp0->serv, sock, retnconf->nc_proto);
 414                         exit(1);
 415                 }
 416         }
 417         /*
 418          * We successfully set up the server over this transport.
 419          * Add this descriptor to the one being polled on.
 420          */
 421         add_to_poll_list(sock, retnconf);
 422 }
 423 
 424 /*
 425  * Set up the SNDR/ncall-ip service over all the available transports.
 426  * Returns -1 for failure, 0 for success.
 427  */
 428 int
 429 do_all(struct protob *protobp,
 430         int (*svc)(int, struct netbuf, struct netconfig *))
 431 {
 432         struct netconfig *nconf;
 433         NCONF_HANDLE *nc;
 434 
 435         if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
 436                 syslog(LOG_ERR, "setnetconfig failed: %m");
 437                 return (-1);
 438         }
 439         while (nconf = getnetconfig(nc)) {
 440                 if ((nconf->nc_flag & NC_VISIBLE) &&
 441                     strcmp(nconf->nc_protofmly, "loopback") != 0 &&
 442                     OK_TPI_TYPE(nconf))
 443                         do_one(nconf->nc_device, nconf->nc_proto, protobp, svc);
 444         }
 445         (void) endnetconfig(nc);
 446         return (0);
 447 }
 448 
 449 /*
 450  * Read the /etc/default/sndr configuration file to determine if the
 451  * client has been configured for number of threads, backlog or transport
 452  * provider.
 453  */
 454 
 455 static void
 456 read_default(void)
 457 {
 458         char *defval, *tmp_str;
 459         int errno;
 460         int tmp;
 461 
 462         /* Fail silently if error in opening the default rdc config file */
 463         if ((defopen(RDCADMIN)) == 0) {
 464                 if ((defval = defread("SNDR_THREADS=")) != NULL) {
 465                         errno = 0;
 466                         tmp = strtol(defval, (char **)NULL, 10);
 467                         if (errno == 0) {
 468                                 max_conns_allowed = tmp;
 469                         }
 470                 }
 471                 if ((defval = defread("SNDR_LISTEN_BACKLOG=")) != NULL) {
 472                         errno = 0;
 473                         tmp = strtol(defval, (char **)NULL, 10);
 474                         if (errno == 0) {
 475                                 listen_backlog = tmp;
 476                         }
 477                 }
 478                 if ((defval = defread("SNDR_TRANSPORT=")) != NULL) {
 479                         errno = 0;
 480                         tmp_str = strdup(defval);
 481                         if (errno == 0) {
 482                                 trans_provider = tmp_str;
 483                         }
 484                 }
 485                 /* close defaults file */
 486                 (void) defopen(NULL);
 487         }
 488 }
 489 #ifdef lint
 490 int
 491 sndrd_lintmain(int ac, char **av)
 492 #else
 493 int
 494 main(int ac, char **av)
 495 #endif
 496 {
 497         const char *dir = "/";
 498         int allflag = 0;
 499         int pid;
 500         int i, rc;
 501         struct protob *protobp0, *protobp;
 502         char **providerp;
 503         char *required;
 504 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
 505         int maxservers;
 506 #endif
 507 
 508         (void) setlocale(LC_ALL, "");
 509 #ifdef  __NCALL__
 510         (void) textdomain("ncall");
 511 #else
 512         (void) textdomain("rdc");
 513 #endif
 514 
 515         progname = basename(av[0]);
 516 
 517 #ifdef  __NCALL__
 518         rc = ncall_check_release(&required);
 519 #else
 520         rc = rdc_check_release(&required);
 521 #endif
 522         if (rc < 0) {
 523                 (void) fprintf(stderr,
 524                     gettext("%s: unable to determine the current "
 525                     "Solaris release: %s\n"), progname, strerror(errno));
 526                 exit(1);
 527         } else if (rc == FALSE) {
 528                 (void) fprintf(stderr,
 529                     gettext("%s: incorrect Solaris release (requires %s)\n"),
 530                     progname, required);
 531                 exit(1);
 532         }
 533 
 534         openlog(progname, LOG_PID|LOG_CONS, LOG_DAEMON);
 535         read_default();
 536 
 537         /*
 538          * Usage: <progname> [-c <number of threads>] [-t protocol] \
 539          *              [-d] [-l <listen backlog>]
 540          */
 541         while ((i = getopt(ac, av, "ac:t:dl:")) != EOF) {
 542                 switch (i) {
 543                         case 'a':
 544                                 allflag = 1;
 545                                 break;
 546                         case 'c':
 547                                 max_conns_allowed = atoi(optarg);
 548                                 if (max_conns_allowed <= 0)
 549                                         max_conns_allowed = 16;
 550                                 break;
 551 
 552                         case 'd':
 553                                 debugflg++;
 554                                 break;
 555 
 556                         case 't':
 557                                 trans_provider = optarg;
 558                                 break;
 559 
 560                         case 'l':
 561                                 listen_backlog = atoi(optarg);
 562                                 if (listen_backlog < 0)
 563                                         listen_backlog = 32;
 564                                 break;
 565 
 566                         default:
 567                                 syslog(LOG_ERR,
 568                                     "Usage: %s [-c <number of threads>] "
 569                                     "[-d] [-t protocol] "
 570                                     "[-l <listen backlog>]\n", progname);
 571                                 exit(1);
 572                                 break;
 573                 }
 574         }
 575 
 576         if (chroot(dir) < 0) {
 577                 syslog(LOG_ERR, "chroot failed: %m");
 578                 exit(1);
 579         }
 580 
 581         if (chdir(dir) < 0) {
 582                 syslog(LOG_ERR, "chdir failed: %m");
 583                 exit(1);
 584         }
 585 
 586         if (!debugflg) {
 587                 pid = fork();
 588                 if (pid < 0) {
 589                         syslog(LOG_ERR, "Fork failed\n");
 590                         exit(1);
 591                 }
 592                 if (pid != 0)
 593                         exit(0);
 594 
 595                 /*
 596                  * Close existing file descriptors, open "/dev/null" as
 597                  * standard input, output, and error, and detach from
 598                  * controlling terminal.
 599                  */
 600 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
 601                 /* use closefrom(3C) from PSARC/2000/193 when possible */
 602                 closefrom(0);
 603 #else
 604                 for (i = 0; i < _NFILE; i++)
 605                         (void) close(i);
 606 #endif
 607                 (void) open("/dev/null", O_RDONLY);
 608                 (void) open("/dev/null", O_WRONLY);
 609                 (void) dup(1);
 610                 (void) setsid();
 611 
 612                 /*
 613                  * ignore all signals apart from SIGTERM.
 614                  */
 615                 for (i = 1; i < _sys_nsig; i++)
 616                         (void) sigset(i, SIG_IGN);
 617 
 618                 (void) sigset(SIGTERM, SIG_DFL);
 619         }
 620 
 621 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
 622         /*
 623          * Set up kernel RPC thread pool for the SNDR/ncall-ip server.
 624          */
 625         maxservers = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
 626         if (sndrsvcpool(maxservers)) {
 627                 (void) syslog(LOG_ERR,
 628                     "Can't set up kernel %s service: %m. Exiting", progname);
 629                 exit(1);
 630         }
 631 
 632         /*
 633          * Set up blocked thread to do LWP creation on behalf of the kernel.
 634          */
 635         if (svcwait(RDC_SVCPOOL_ID)) {
 636                 (void) syslog(LOG_ERR,
 637                     "Can't set up %s pool creator: %m, Exiting", progname);
 638                 exit(1);
 639         }
 640 #endif
 641 
 642         /*
 643          * Build a protocol block list for registration.
 644          */
 645         protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
 646         protobp->serv = RDC_SVC_NAME;
 647         protobp->versmin = RDC_VERS_MIN;
 648         protobp->versmax = RDC_VERS_MAX;
 649         protobp->program = RDC_PROGRAM;
 650         protobp->next = (struct protob *)NULL;
 651 
 652         if (allflag) {
 653                 if (do_all(protobp0, rdcsvc) == -1)
 654                         exit(1);
 655         } else if (trans_provider)
 656                 do_one(trans_provider, NULL, protobp0, rdcsvc);
 657         else {
 658                 for (providerp = defaultproviders;
 659                     *providerp != NULL; providerp++) {
 660                         trans_provider = *providerp;
 661                         do_one(trans_provider, NULL, protobp0, rdcsvc);
 662                 }
 663         }
 664 
 665 done:
 666         free(protobp);
 667 
 668         end_listen_fds = num_fds;
 669         /*
 670          * Poll for non-data control events on the transport descriptors.
 671          */
 672         poll_for_action();
 673 
 674         syslog(LOG_ERR, "%s fatal server error\n", progname);
 675 
 676         return (-1);
 677 }
 678 
 679 static int
 680 reuseaddr(int fd)
 681 {
 682         struct t_optmgmt req, resp;
 683         struct opthdr *opt;
 684         char reqbuf[128];
 685         int *ip;
 686 
 687         /* LINTED pointer alignment */
 688         opt = (struct opthdr *)reqbuf;
 689         opt->level = SOL_SOCKET;
 690         opt->name = SO_REUSEADDR;
 691         opt->len = sizeof (int);
 692 
 693         /* LINTED pointer alignment */
 694         ip = (int *)&reqbuf[sizeof (struct opthdr)];
 695         *ip = 1;
 696 
 697         req.flags = T_NEGOTIATE;
 698         req.opt.len = sizeof (struct opthdr) + opt->len;
 699         req.opt.buf = (char *)opt;
 700 
 701         resp.flags = 0;
 702         resp.opt.buf = reqbuf;
 703         resp.opt.maxlen = sizeof (reqbuf);
 704 
 705         if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
 706                 if (t_errno == TSYSERR) {
 707                         syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %m\n");
 708                 } else {
 709                         syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %s\n",
 710                             t_errlist[t_errno]);
 711                 }
 712                 return (-1);
 713         }
 714         return (0);
 715 }
 716 
 717 /*
 718  * poll on the open transport descriptors for events and errors.
 719  */
 720 void
 721 poll_for_action(void)
 722 {
 723         int nfds;
 724         int i;
 725 
 726         /*
 727          * Keep polling until all transports have been closed. When this
 728          * happens, we return.
 729          */
 730         while ((int)num_fds > 0) {
 731                 nfds = poll(poll_array, num_fds, INFTIM);
 732                 switch (nfds) {
 733                 case 0:
 734                         continue;
 735 
 736                 case -1:
 737                         /*
 738                          * Some errors from poll could be
 739                          * due to temporary conditions, and we try to
 740                          * be robust in the face of them. Other
 741                          * errors (should never happen in theory)
 742                          * are fatal (eg. EINVAL, EFAULT).
 743                          */
 744                         switch (errno) {
 745                         case EINTR:
 746                                 continue;
 747 
 748                         case EAGAIN:
 749                         case ENOMEM:
 750                                 (void) sleep(10);
 751                                 continue;
 752 
 753                         default:
 754                                 (void) syslog(LOG_ERR,
 755                                     "poll failed: %m. Exiting");
 756                                 exit(1);
 757                         }
 758                 default:
 759                         break;
 760                 }
 761 
 762                 /*
 763                  * Go through the poll list looking for events.
 764                  */
 765                 for (i = 0; i < num_fds && nfds > 0; i++) {
 766                         if (poll_array[i].revents) {
 767                                 nfds--;
 768                                 /*
 769                                  * We have a message, so try to read it.
 770                                  * Record the error return in errno,
 771                                  * so that syslog(LOG_ERR, "...%m")
 772                                  * dumps the corresponding error string.
 773                                  */
 774                                 if (conn_polled[i].nc.nc_semantics ==
 775                                     NC_TPI_CLTS) {
 776                                         errno = do_poll_clts_action(
 777                                             poll_array[i].fd, i);
 778                                 } else {
 779                                         errno = do_poll_cots_action(
 780                                             poll_array[i].fd, i);
 781                                 }
 782 
 783                                 if (errno == 0)
 784                                         continue;
 785                                 /*
 786                                  * Most returned error codes mean that there is
 787                                  * fatal condition which we can only deal with
 788                                  * by closing the transport.
 789                                  */
 790                                 if (errno != EAGAIN && errno != ENOMEM) {
 791                                         (void) syslog(LOG_ERR,
 792                                             "Error (%m) reading descriptor %d"
 793                                             "/transport %s. Closing it.",
 794                                             poll_array[i].fd,
 795                                             conn_polled[i].nc.nc_proto);
 796                                         (void) t_close(poll_array[i].fd);
 797                                         remove_from_poll_list(poll_array[i].fd);
 798                                 } else if (errno == ENOMEM)
 799                                         (void) sleep(5);
 800                         }
 801                 }
 802         }
 803 
 804         (void) syslog(LOG_ERR,
 805             "All transports have been closed with errors. Exiting.");
 806 }
 807 
 808 /*
 809  * Allocate poll/transport array entries for this descriptor.
 810  */
 811 static void
 812 add_to_poll_list(int fd, struct netconfig *nconf)
 813 {
 814         static int poll_array_size = 0;
 815 
 816         /*
 817          * If the arrays are full, allocate new ones.
 818          */
 819         if (num_fds == poll_array_size) {
 820                 struct pollfd *tpa;
 821                 struct conn_entry *tnp;
 822 
 823                 if (poll_array_size != 0) {
 824                         tpa = poll_array;
 825                         tnp = conn_polled;
 826                 } else
 827                         tpa = (struct pollfd *)0;
 828 
 829                 poll_array_size += POLL_ARRAY_INC_SIZE;
 830 
 831                 /*
 832                  * Allocate new arrays.
 833                  */
 834                 poll_array = (struct pollfd *)
 835                     malloc(poll_array_size * sizeof (struct pollfd) + 256);
 836                 conn_polled = (struct conn_entry *)
 837                     malloc(poll_array_size * sizeof (struct conn_entry) + 256);
 838                 if (poll_array == (struct pollfd *)NULL ||
 839                     conn_polled == (struct conn_entry *)NULL) {
 840                         syslog(LOG_ERR, "malloc failed for poll array");
 841                         exit(1);
 842                 }
 843 
 844                 /*
 845                  * Copy the data of the old ones into new arrays, and
 846                  * free the old ones.
 847                  * num_fds is guaranteed to be less than
 848                  * poll_array_size, so this memcpy is safe.
 849                  */
 850                 if (tpa) {
 851                         (void) memcpy((void *)poll_array, (void *)tpa,
 852                             num_fds * sizeof (struct pollfd));
 853                         (void) memcpy((void *)conn_polled, (void *)tnp,
 854                             num_fds * sizeof (struct conn_entry));
 855                         free((void *)tpa);
 856                         free((void *)tnp);
 857                 }
 858         }
 859 
 860         /*
 861          * Set the descriptor and event list. All possible events are
 862          * polled for.
 863          */
 864         poll_array[num_fds].fd = fd;
 865         poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
 866 
 867         /*
 868          * Copy the transport data over too.
 869          */
 870         conn_polled[num_fds].nc = *nconf;       /* structure copy */
 871         conn_polled[num_fds].closing = 0;
 872 
 873         /*
 874          * Set the descriptor to non-blocking. Avoids a race
 875          * between data arriving on the stream and then having it
 876          * flushed before we can read it.
 877          */
 878         if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
 879                 (void) syslog(LOG_ERR,
 880                     "fcntl(file desc. %d/transport %s, F_SETFL, "
 881                     "O_NONBLOCK): %m. Exiting",
 882                     num_fds, nconf->nc_proto);
 883                 exit(1);
 884         }
 885 
 886         /*
 887          * Count this descriptor.
 888          */
 889         ++num_fds;
 890 }
 891 
 892 static void
 893 remove_from_poll_list(int fd)
 894 {
 895         int i;
 896         int num_to_copy;
 897 
 898         for (i = 0; i < num_fds; i++) {
 899                 if (poll_array[i].fd == fd) {
 900                         --num_fds;
 901                         num_to_copy = num_fds - i;
 902                         (void) memcpy((void *)&poll_array[i],
 903                             (void *)&poll_array[i+1],
 904                             num_to_copy * sizeof (struct pollfd));
 905                         (void) memset((void *)&poll_array[num_fds], 0,
 906                             sizeof (struct pollfd));
 907                         (void) memcpy((void *)&conn_polled[i],
 908                             (void *)&conn_polled[i+1],
 909                             num_to_copy * sizeof (struct conn_entry));
 910                         (void) memset((void *)&conn_polled[num_fds], 0,
 911                             sizeof (struct conn_entry));
 912                         return;
 913                 }
 914         }
 915         syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
 916 
 917 }
 918 
 919 static void
 920 conn_close_oldest(void)
 921 {
 922         int fd;
 923         int i1;
 924 
 925         /*
 926          * Find the oldest connection that is not already in the
 927          * process of shutting down.
 928          */
 929         for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
 930                 if (i1 >= num_fds)
 931                         return;
 932                 if (conn_polled[i1].closing == 0)
 933                         break;
 934         }
 935 #ifdef DEBUG
 936         (void) printf("too many connections (%d), releasing oldest (%d)\n",
 937             num_conns, poll_array[i1].fd);
 938 #else
 939         syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
 940             num_conns, poll_array[i1].fd);
 941 #endif
 942         fd = poll_array[i1].fd;
 943         if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
 944                 /*
 945                  * For politeness, send a T_DISCON_REQ to the transport
 946                  * provider.  We close the stream anyway.
 947                  */
 948                 (void) t_snddis(fd, (struct t_call *)0);
 949                 num_conns--;
 950                 remove_from_poll_list(fd);
 951                 (void) t_close(fd);
 952         } else {
 953                 /*
 954                  * For orderly release, we do not close the stream
 955                  * until the T_ORDREL_IND arrives to complete
 956                  * the handshake.
 957                  */
 958                 if (t_sndrel(fd) == 0)
 959                         conn_polled[i1].closing = 1;
 960         }
 961 }
 962 
 963 static boolean_t
 964 conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
 965 {
 966         struct conn_ind *conn;
 967         struct conn_ind *next_conn;
 968 
 969         conn = (struct conn_ind *)malloc(sizeof (*conn));
 970         if (conn == NULL) {
 971                 syslog(LOG_ERR, "malloc for listen indication failed");
 972                 return (FALSE);
 973         }
 974 
 975         /* LINTED pointer alignment */
 976         conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
 977         if (conn->conn_call == NULL) {
 978                 free((char *)conn);
 979                 rdcd_log_tli_error("t_alloc", fd, nconf);
 980                 return (FALSE);
 981         }
 982 
 983         if (t_listen(fd, conn->conn_call) == -1) {
 984                 rdcd_log_tli_error("t_listen", fd, nconf);
 985                 (void) t_free((char *)conn->conn_call, T_CALL);
 986                 free((char *)conn);
 987                 return (FALSE);
 988         }
 989 
 990         if (conn->conn_call->udata.len > 0) {
 991                 syslog(LOG_WARNING,
 992                     "rejecting inbound connection(%s) with %d bytes "
 993                     "of connect data",
 994                     nconf->nc_proto, conn->conn_call->udata.len);
 995 
 996                 conn->conn_call->udata.len = 0;
 997                 (void) t_snddis(fd, conn->conn_call);
 998                 (void) t_free((char *)conn->conn_call, T_CALL);
 999                 free((char *)conn);
1000                 return (FALSE);
1001         }
1002 
1003         if ((next_conn = *connp) != NULL) {
1004                 next_conn->conn_prev->conn_next = conn;
1005                 conn->conn_next = next_conn;
1006                 conn->conn_prev = next_conn->conn_prev;
1007                 next_conn->conn_prev = conn;
1008         } else {
1009                 conn->conn_next = conn;
1010                 conn->conn_prev = conn;
1011                 *connp = conn;
1012         }
1013         return (TRUE);
1014 }
1015 
1016 static int
1017 discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1018 {
1019         struct conn_ind *conn;
1020         struct t_discon discon;
1021 
1022         discon.udata.buf = (char *)0;
1023         discon.udata.maxlen = 0;
1024         if (t_rcvdis(fd, &discon) == -1) {
1025                 rdcd_log_tli_error("t_rcvdis", fd, nconf);
1026                 return (-1);
1027         }
1028 
1029         conn = *connp;
1030         if (conn == NULL)
1031                 return (0);
1032 
1033         do {
1034                 if (conn->conn_call->sequence == discon.sequence) {
1035                         if (conn->conn_next == conn)
1036                                 *connp = (struct conn_ind *)0;
1037                         else {
1038                                 if (conn == *connp) {
1039                                         *connp = conn->conn_next;
1040                                 }
1041                                 conn->conn_next->conn_prev = conn->conn_prev;
1042                                 conn->conn_prev->conn_next = conn->conn_next;
1043                         }
1044                         free((char *)conn);
1045                         break;
1046                 }
1047                 conn = conn->conn_next;
1048         } while (conn != *connp);
1049 
1050         return (0);
1051 }
1052 
1053 static void
1054 cots_listen_event(int fd, int conn_index)
1055 {
1056         struct t_call *call;
1057         struct conn_ind *conn;
1058         struct conn_ind *conn_head;
1059         int event;
1060         struct netconfig *nconf = &conn_polled[conn_index].nc;
1061         int new_fd;
1062         struct netbuf addrmask;
1063         int ret = 0;
1064 
1065         conn_head = NULL;
1066         (void) conn_get(fd, nconf, &conn_head);
1067 
1068         while ((conn = conn_head) != NULL) {
1069                 conn_head = conn->conn_next;
1070                 if (conn_head == conn)
1071                         conn_head = NULL;
1072                 else {
1073                         conn_head->conn_prev = conn->conn_prev;
1074                         conn->conn_prev->conn_next = conn_head;
1075                 }
1076                 call = conn->conn_call;
1077                 free(conn);
1078 
1079                 /*
1080                  * If we have already accepted the maximum number of
1081                  * connections allowed on the command line, then drop
1082                  * the oldest connection (for any protocol) before
1083                  * accepting the new connection.  Unless explicitly
1084                  * set on the command line, max_conns_allowed is -1.
1085                  */
1086                 if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
1087                         conn_close_oldest();
1088 
1089                 /*
1090                  * Create a new transport endpoint for the same proto as
1091                  * the listener.
1092                  */
1093                 new_fd = rdc_transport_open(nconf);
1094                 if (new_fd == -1) {
1095                         call->udata.len = 0;
1096                         (void) t_snddis(fd, call);
1097                         (void) t_free((char *)call, T_CALL);
1098                         syslog(LOG_ERR, "Cannot establish transport over %s",
1099                             nconf->nc_device);
1100                         continue;
1101                 }
1102 
1103                 /* Bind to a generic address/port for the accepting stream. */
1104                 if (t_bind(new_fd, NULL, NULL) == -1) {
1105                         rdcd_log_tli_error("t_bind", new_fd, nconf);
1106                         call->udata.len = 0;
1107                         (void) t_snddis(fd, call);
1108                         (void) t_free((char *)call, T_CALL);
1109                         (void) t_close(new_fd);
1110                         continue;
1111                 }
1112 
1113                 while (t_accept(fd, new_fd, call) == -1) {
1114                         if (t_errno != TLOOK) {
1115                                 rdcd_log_tli_error("t_accept", fd, nconf);
1116                                 call->udata.len = 0;
1117                                 (void) t_snddis(fd, call);
1118                                 (void) t_free((char *)call, T_CALL);
1119                                 (void) t_close(new_fd);
1120                                 goto do_next_conn;
1121                         }
1122                         while (event = t_look(fd)) {
1123                                 switch (event) {
1124                                 case T_LISTEN:
1125                                         (void) conn_get(fd, nconf, &conn_head);
1126                                         continue;
1127 
1128                                 case T_DISCONNECT:
1129                                         (void) discon_get(fd, nconf,
1130                                             &conn_head);
1131                                         continue;
1132 
1133                                 default:
1134                                         syslog(LOG_ERR,
1135                                             "unexpected event 0x%x during "
1136                                             "accept processing (%s)",
1137                                             event, nconf->nc_proto);
1138                                         call->udata.len = 0;
1139                                         (void) t_snddis(fd, call);
1140                                         (void) t_free((char *)call, T_CALL);
1141                                         (void) t_close(new_fd);
1142                                         goto do_next_conn;
1143                                 }
1144                         }
1145                 }
1146 
1147                 if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
1148                         (void) syslog(LOG_ERR, "Cannot set address mask for %s",
1149                             nconf->nc_netid);
1150                         (void) t_snddis(new_fd, NULL);
1151                         (void) t_free((char *)call, T_CALL);
1152                         (void) t_close(new_fd);
1153                         continue;
1154                 }
1155 
1156                 /* Tell kRPC about the new stream. */
1157                 ret = (*Mysvc)(new_fd, addrmask, nconf);
1158                 if (ret < 0) {
1159                         syslog(LOG_ERR,
1160                             "unable to register with kernel rpc: %m");
1161                         free(addrmask.buf);
1162                         (void) t_snddis(new_fd, NULL);
1163                         (void) t_free((char *)call, T_CALL);
1164                         (void) t_close(new_fd);
1165                         goto do_next_conn;
1166                 }
1167 
1168                 free(addrmask.buf);
1169                 (void) t_free((char *)call, T_CALL);
1170 
1171                 /*
1172                  * Poll on the new descriptor so that we get disconnect
1173                  * and orderly release indications.
1174                  */
1175                 num_conns++;
1176                 add_to_poll_list(new_fd, nconf);
1177 
1178                 /* Reset nconf in case it has been moved. */
1179                 nconf = &conn_polled[conn_index].nc;
1180 do_next_conn:;
1181         }
1182 }
1183 
1184 static int
1185 do_poll_cots_action(int fd, int conn_index)
1186 {
1187         char buf[256];
1188         int event;
1189         int i1;
1190         int flags;
1191         struct conn_entry *connent = &conn_polled[conn_index];
1192         struct netconfig *nconf = &(connent->nc);
1193         const char *errorstr;
1194 
1195         while (event = t_look(fd)) {
1196                 switch (event) {
1197                 case T_LISTEN:
1198                         cots_listen_event(fd, conn_index);
1199                         break;
1200 
1201                 case T_DATA:
1202                         /*
1203                          * Receive a private notification from CONS rpcmod.
1204                          */
1205                         i1 = t_rcv(fd, buf, sizeof (buf), &flags);
1206                         if (i1 == -1) {
1207                                 syslog(LOG_ERR, "t_rcv failed");
1208                                 break;
1209                         }
1210                         if (i1 < sizeof (int))
1211                                 break;
1212                         i1 = BE32_TO_U32(buf);
1213                         if (i1 == 1 || i1 == 2) {
1214                                 /*
1215                                  * This connection has been idle for too long,
1216                                  * so release it as politely as we can.  If we
1217                                  * have already initiated an orderly release
1218                                  * and we get notified that the stream is
1219                                  * still idle, pull the plug.  This prevents
1220                                  * hung connections from continuing to consume
1221                                  * resources.
1222                                  */
1223                                 if (nconf->nc_semantics == NC_TPI_COTS ||
1224                                     connent->closing != 0) {
1225                                         (void) t_snddis(fd, (struct t_call *)0);
1226                                         goto fdclose;
1227                                 }
1228                                 /*
1229                                  * For NC_TPI_COTS_ORD, the stream is closed
1230                                  * and removed from the poll list when the
1231                                  * T_ORDREL is received from the provider.  We
1232                                  * don't wait for it here because it may take
1233                                  * a while for the transport to shut down.
1234                                  */
1235                                 if (t_sndrel(fd) == -1) {
1236                                         syslog(LOG_ERR,
1237                                         "unable to send orderly release %m");
1238                                 }
1239                                 connent->closing = 1;
1240                         } else
1241                                 syslog(LOG_ERR,
1242                                     "unexpected event from CONS rpcmod %d", i1);
1243                         break;
1244 
1245                 case T_ORDREL:
1246                         /* Perform an orderly release. */
1247                         if (t_rcvrel(fd) == 0) {
1248                                 /* T_ORDREL on listen fd's should be ignored */
1249                                 if (!is_listen_fd_index(fd)) {
1250                                         (void) t_sndrel(fd);
1251                                         goto fdclose;
1252                                 }
1253                                 break;
1254 
1255                         } else if (t_errno == TLOOK) {
1256                                 break;
1257                         } else {
1258                                 rdcd_log_tli_error("t_rcvrel", fd, nconf);
1259                                 /*
1260                                  * check to make sure we do not close
1261                                  * listen fd
1262                                  */
1263                                 if (!is_listen_fd_index(fd))
1264                                         break;
1265                                 else
1266                                         goto fdclose;
1267                         }
1268 
1269                 case T_DISCONNECT:
1270                         if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
1271                                 rdcd_log_tli_error("t_rcvdis", fd, nconf);
1272 
1273                         /*
1274                          * T_DISCONNECT on listen fd's should be ignored.
1275                          */
1276                         if (!is_listen_fd_index(fd))
1277                                 break;
1278                         else
1279                                 goto fdclose;
1280 
1281                 case T_ERROR:
1282                 default:
1283                         if (event == T_ERROR || t_errno == TSYSERR) {
1284                                 if ((errorstr = strerror(errno)) == NULL) {
1285                                         (void) snprintf(buf, sizeof (buf),
1286                                             "Unknown error num %d", errno);
1287                                         errorstr = (const char *)buf;
1288                                 }
1289                         } else if (event == -1)
1290                                 errorstr = t_strerror(t_errno);
1291                         else
1292                                 errorstr = "";
1293 #ifdef DEBUG
1294                         syslog(LOG_ERR,
1295                             "unexpected TLI event (0x%x) on "
1296                             "connection-oriented transport(%s, %d):%s",
1297                             event, nconf->nc_proto, fd, errorstr);
1298 #endif
1299 
1300 fdclose:
1301                         num_conns--;
1302                         remove_from_poll_list(fd);
1303                         (void) t_close(fd);
1304                         return (0);
1305                 }
1306         }
1307 
1308         return (0);
1309 }
1310 
1311 
1312 /*
1313  * Called to read and interpret the event on a connectionless descriptor.
1314  * Returns 0 if successful, or a UNIX error code if failure.
1315  */
1316 static int
1317 do_poll_clts_action(int fd, int conn_index)
1318 {
1319         int error;
1320         int ret;
1321         int flags;
1322         struct netconfig *nconf = &conn_polled[conn_index].nc;
1323         static struct t_unitdata *unitdata = NULL;
1324         static struct t_uderr *uderr = NULL;
1325         static int oldfd = -1;
1326         struct nd_hostservlist *host = NULL;
1327         struct strbuf ctl[1], data[1];
1328         /*
1329          * We just need to have some space to consume the
1330          * message in the event we can't use the TLI interface to do the
1331          * job.
1332          *
1333          * We flush the message using getmsg(). For the control part
1334          * we allocate enough for any TPI header plus 32 bytes for address
1335          * and options. For the data part, there is nothing magic about
1336          * the size of the array, but 256 bytes is probably better than
1337          * 1 byte, and we don't expect any data portion anyway.
1338          *
1339          * If the array sizes are too small, we handle this because getmsg()
1340          * (called to consume the message) will return MOREDATA|MORECTL.
1341          * Thus we just call getmsg() until it's read the message.
1342          */
1343         char ctlbuf[sizeof (union T_primitives) + 32];
1344         char databuf[256];
1345 
1346         /*
1347          * If this is the same descriptor as the last time
1348          * do_poll_clts_action was called, we can save some
1349          * de-allocation and allocation.
1350          */
1351         if (oldfd != fd) {
1352                 oldfd = fd;
1353 
1354                 if (unitdata) {
1355                         (void) t_free((char *)unitdata, T_UNITDATA);
1356                         unitdata = NULL;
1357                 }
1358                 if (uderr) {
1359                         (void) t_free((char *)uderr, T_UDERROR);
1360                         uderr = NULL;
1361                 }
1362         }
1363 
1364         /*
1365          * Allocate a unitdata structure for receiving the event.
1366          */
1367         if (unitdata == NULL) {
1368                 /* LINTED pointer alignment */
1369                 unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
1370                 if (unitdata == NULL) {
1371                         if (t_errno == TSYSERR) {
1372                                 /*
1373                                  * Save the error code across
1374                                  * syslog(), just in case
1375                                  * syslog() gets its own error
1376                                  * and therefore overwrites errno.
1377                                  */
1378                                 error = errno;
1379                                 (void) syslog(LOG_ERR,
1380                                     "t_alloc(file descriptor %d/transport %s, "
1381                                     "T_UNITDATA) failed: %m",
1382                                     fd, nconf->nc_proto);
1383                                 return (error);
1384                         }
1385                         (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/"
1386                             "transport %s, T_UNITDATA) failed TLI error %d",
1387                             fd, nconf->nc_proto, t_errno);
1388                         goto flush_it;
1389                 }
1390         }
1391 
1392 try_again:
1393         flags = 0;
1394 
1395         /*
1396          * The idea is we wait for T_UNITDATA_IND's. Of course,
1397          * we don't get any, because rpcmod filters them out.
1398          * However, we need to call t_rcvudata() to let TLI
1399          * tell us we have a T_UDERROR_IND.
1400          *
1401          * algorithm is:
1402          *      t_rcvudata(), expecting TLOOK.
1403          *      t_look(), expecting T_UDERR.
1404          *      t_rcvuderr(), expecting success (0).
1405          *      expand destination address into ASCII,
1406          *      and dump it.
1407          */
1408 
1409         ret = t_rcvudata(fd, unitdata, &flags);
1410         if (ret == 0 || t_errno == TBUFOVFLW) {
1411                 (void) syslog(LOG_WARNING, "t_rcvudata(file descriptor %d/"
1412                     "transport %s) got unexpected data, %d bytes",
1413                     fd, nconf->nc_proto, unitdata->udata.len);
1414 
1415                 /*
1416                  * Even though we don't expect any data, in case we do,
1417                  * keep reading until there is no more.
1418                  */
1419                 if (flags & T_MORE)
1420                         goto try_again;
1421 
1422                 return (0);
1423         }
1424 
1425         switch (t_errno) {
1426         case TNODATA:
1427                 return (0);
1428         case TSYSERR:
1429                 /*
1430                  * System errors are returned to caller.
1431                  * Save the error code across
1432                  * syslog(), just in case
1433                  * syslog() gets its own error
1434                  * and therefore overwrites errno.
1435                  */
1436                 error = errno;
1437                 (void) syslog(LOG_ERR,
1438                     "t_rcvudata(file descriptor %d/transport %s) %m",
1439                     fd, nconf->nc_proto);
1440                 return (error);
1441         case TLOOK:
1442                 break;
1443         default:
1444                 (void) syslog(LOG_ERR,
1445                     "t_rcvudata(file descriptor %d/transport %s) TLI error %d",
1446                     fd, nconf->nc_proto, t_errno);
1447                 goto flush_it;
1448         }
1449 
1450         ret = t_look(fd);
1451         switch (ret) {
1452         case 0:
1453                 return (0);
1454         case -1:
1455                 /*
1456                  * System errors are returned to caller.
1457                  */
1458                 if (t_errno == TSYSERR) {
1459                         /*
1460                          * Save the error code across
1461                          * syslog(), just in case
1462                          * syslog() gets its own error
1463                          * and therefore overwrites errno.
1464                          */
1465                         error = errno;
1466                         (void) syslog(LOG_ERR,
1467                             "t_look(file descriptor %d/transport %s) %m",
1468                             fd, nconf->nc_proto);
1469                         return (error);
1470                 }
1471                 (void) syslog(LOG_ERR,
1472                     "t_look(file descriptor %d/transport %s) TLI error %d",
1473                     fd, nconf->nc_proto, t_errno);
1474                 goto flush_it;
1475         case T_UDERR:
1476                 break;
1477         default:
1478                 (void) syslog(LOG_WARNING, "t_look(file descriptor %d/"
1479                     "transport %s) returned %d not T_UDERR (%d)",
1480                     fd, nconf->nc_proto, ret, T_UDERR);
1481         }
1482 
1483         if (uderr == NULL) {
1484                 /* LINTED pointer alignment */
1485                 uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
1486                 if (uderr == NULL) {
1487                         if (t_errno == TSYSERR) {
1488                                 /*
1489                                  * Save the error code across
1490                                  * syslog(), just in case
1491                                  * syslog() gets its own error
1492                                  * and therefore overwrites errno.
1493                                  */
1494                                 error = errno;
1495                                 (void) syslog(LOG_ERR,
1496                                     "t_alloc(file descriptor %d/transport %s, "
1497                                     "T_UDERROR) failed: %m",
1498                                     fd, nconf->nc_proto);
1499                                 return (error);
1500                         }
1501                         (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/"
1502                             "transport %s, T_UDERROR) failed TLI error: %d",
1503                             fd, nconf->nc_proto, t_errno);
1504                         goto flush_it;
1505                 }
1506         }
1507 
1508         ret = t_rcvuderr(fd, uderr);
1509         if (ret == 0) {
1510 
1511                 /*
1512                  * Save the datagram error in errno, so that the
1513                  * %m argument to syslog picks up the error string.
1514                  */
1515                 errno = uderr->error;
1516 
1517                 /*
1518                  * Log the datagram error, then log the host that
1519                  * probably triggerred. Cannot log both in the
1520                  * same transaction because of packet size limitations
1521                  * in /dev/log.
1522                  */
1523                 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1524                     "%s response over <file descriptor %d/transport %s> "
1525                     "generated error: %m",
1526                     progname, fd, nconf->nc_proto);
1527 
1528                 /*
1529                  * Try to map the client's address back to a
1530                  * name.
1531                  */
1532                 ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
1533                 if (ret != -1 && host && host->h_cnt > 0 &&
1534                     host->h_hostservs) {
1535                 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1536                     "Bad %s response was sent to client with "
1537                     "host name: %s; service port: %s",
1538                     progname, host->h_hostservs->h_host,
1539                     host->h_hostservs->h_serv);
1540                 } else {
1541                         int i, j;
1542                         char *buf;
1543                         char *hex = "0123456789abcdef";
1544 
1545                         /*
1546                          * Mapping failed, print the whole thing
1547                          * in ASCII hex.
1548                          */
1549                         buf = (char *)malloc(uderr->addr.len * 2 + 1);
1550                         for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
1551                                 buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
1552                                 buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
1553                         }
1554                         buf[j] = '\0';
1555                         (void) syslog((errno == ECONNREFUSED) ?
1556                             LOG_DEBUG : LOG_WARNING,
1557                             "Bad %s response was sent to client with "
1558                             "transport address: 0x%s",
1559                             progname, buf);
1560                         free((void *)buf);
1561                 }
1562 
1563                 if (ret == 0 && host != NULL)
1564                         netdir_free((void *)host, ND_HOSTSERVLIST);
1565                 return (0);
1566         }
1567 
1568         switch (t_errno) {
1569         case TNOUDERR:
1570                 goto flush_it;
1571         case TSYSERR:
1572                 /*
1573                  * System errors are returned to caller.
1574                  * Save the error code across
1575                  * syslog(), just in case
1576                  * syslog() gets its own error
1577                  * and therefore overwrites errno.
1578                  */
1579                 error = errno;
1580                 (void) syslog(LOG_ERR,
1581                     "t_rcvuderr(file descriptor %d/transport %s) %m",
1582                     fd, nconf->nc_proto);
1583                 return (error);
1584         default:
1585                 (void) syslog(LOG_ERR,
1586                     "t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
1587                     fd, nconf->nc_proto, t_errno);
1588                 goto flush_it;
1589         }
1590 
1591 flush_it:
1592         /*
1593          * If we get here, then we could not cope with whatever message
1594          * we attempted to read, so flush it. If we did read a message,
1595          * and one isn't present, that is all right, because fd is in
1596          * nonblocking mode.
1597          */
1598         (void) syslog(LOG_ERR,
1599             "Flushing one input message from <file descriptor %d/transport %s>",
1600             fd, nconf->nc_proto);
1601 
1602         /*
1603          * Read and discard the message. Do this this until there is
1604          * no more control/data in the message or until we get an error.
1605          */
1606         do {
1607                 ctl->maxlen = sizeof (ctlbuf);
1608                 ctl->buf = ctlbuf;
1609                 data->maxlen = sizeof (databuf);
1610                 data->buf = databuf;
1611                 flags = 0;
1612                 ret = getmsg(fd, ctl, data, &flags);
1613                 if (ret == -1)
1614                         return (errno);
1615         } while (ret != 0);
1616 
1617         return (0);
1618 }
1619 
1620 /*
1621  * Establish service thread.
1622  */
1623 static int
1624 rdcsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
1625 {
1626 #ifdef  __NCALL__
1627         struct ncall_svc_args nsa;
1628 #else   /* !__NCALL__ */
1629         struct rdc_svc_args nsa;
1630         _rdc_ioctl_t rdc_args = { 0, };
1631 #endif  /* __NCALL__ */
1632 
1633         nsa.fd = fd;
1634         nsa.nthr = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
1635         (void) strncpy(nsa.netid, nconf->nc_netid, sizeof (nsa.netid));
1636         nsa.addrmask.len = addrmask.len;
1637         nsa.addrmask.maxlen = addrmask.maxlen;
1638         nsa.addrmask.buf = addrmask.buf;
1639 
1640 #ifdef  __NCALL__
1641         return (sndrsys(NC_IOC_SERVER, &nsa));
1642 #else   /* !__NCALL__ */
1643         rdc_args.arg0 = (long)&nsa;
1644         return (sndrsys(RDC_ENABLE_SVR, &rdc_args));
1645 #endif  /* __NCALL__ */
1646 }
1647 
1648 
1649 
1650 static int
1651 nofile_increase(int limit)
1652 {
1653         struct rlimit rl;
1654 
1655         if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
1656                 syslog(LOG_ERR,
1657                     "nofile_increase() getrlimit of NOFILE failed: %m");
1658                 return (-1);
1659         }
1660 
1661         if (limit > 0)
1662                 rl.rlim_cur = limit;
1663         else
1664                 rl.rlim_cur += NOFILE_INC_SIZE;
1665 
1666         if (rl.rlim_cur > rl.rlim_max && rl.rlim_max != RLIM_INFINITY)
1667                 rl.rlim_max = rl.rlim_cur;
1668 
1669         if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
1670                 syslog(LOG_ERR,
1671                     "nofile_increase() setrlimit of NOFILE to %d failed: %m",
1672                     rl.rlim_cur);
1673                 return (-1);
1674         }
1675 
1676         return (0);
1677 }
1678 
1679 int
1680 rdcd_bindit(struct netconfig *nconf, struct netbuf **addr,
1681     struct nd_hostserv *hs, int backlog)
1682 {
1683         int fd;
1684         struct t_bind *ntb;
1685         struct t_bind tb;
1686         struct nd_addrlist *addrlist;
1687         struct t_optmgmt req, resp;
1688         struct opthdr *opt;
1689         char reqbuf[128];
1690 
1691         if ((fd = rdc_transport_open(nconf)) == -1) {
1692                 syslog(LOG_ERR, "cannot establish transport service over %s",
1693                     nconf->nc_device);
1694                 return (-1);
1695         }
1696 
1697         addrlist = (struct nd_addrlist *)NULL;
1698         if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
1699                 if (strncmp(nconf->nc_netid, "udp", 3) != 0) {
1700                         syslog(LOG_ERR, "Cannot get address for transport "
1701                             "%s host %s service %s",
1702                             nconf->nc_netid, hs->h_host, hs->h_serv);
1703                 }
1704                 (void) t_close(fd);
1705                 return (-1);
1706         }
1707 
1708         if (strcmp(nconf->nc_proto, "tcp") == 0) {
1709                 /*
1710                  * If we're running over TCP, then set the
1711                  * SO_REUSEADDR option so that we can bind
1712                  * to our preferred address even if previously
1713                  * left connections exist in FIN_WAIT states.
1714                  * This is somewhat bogus, but otherwise you have
1715                  * to wait 2 minutes to restart after killing it.
1716                  */
1717                 if (reuseaddr(fd) == -1) {
1718                         syslog(LOG_WARNING,
1719                             "couldn't set SO_REUSEADDR option on transport");
1720                 }
1721         }
1722 
1723         if (nconf->nc_semantics == NC_TPI_CLTS)
1724                 tb.qlen = 0;
1725         else
1726                 tb.qlen = backlog;
1727 
1728         /* LINTED pointer alignment */
1729         ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
1730         if (ntb == (struct t_bind *)NULL) {
1731                 syslog(LOG_ERR, "t_alloc failed:  t_errno %d, %m", t_errno);
1732                 (void) t_close(fd);
1733                 netdir_free((void *)addrlist, ND_ADDRLIST);
1734                 return (-1);
1735         }
1736 
1737         tb.addr = *(addrlist->n_addrs);              /* structure copy */
1738 
1739         if (t_bind(fd, &tb, ntb) == -1) {
1740                 syslog(LOG_ERR, "t_bind failed:  t_errno %d, %m", t_errno);
1741                 (void) t_free((char *)ntb, T_BIND);
1742                 netdir_free((void *)addrlist, ND_ADDRLIST);
1743                 (void) t_close(fd);
1744                 return (-1);
1745         }
1746 
1747         /* make sure we bound to the right address */
1748         if (tb.addr.len != ntb->addr.len ||
1749             memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0) {
1750                 syslog(LOG_ERR, "t_bind to wrong address");
1751                 (void) t_free((char *)ntb, T_BIND);
1752                 netdir_free((void *)addrlist, ND_ADDRLIST);
1753                 (void) t_close(fd);
1754                 return (-1);
1755         }
1756 
1757         *addr = &ntb->addr;
1758         netdir_free((void *)addrlist, ND_ADDRLIST);
1759 
1760         if (strcmp(nconf->nc_proto, "tcp") == 0 ||
1761             strcmp(nconf->nc_proto, "tcp6") == 0) {
1762                 /*
1763                  * Disable the Nagle algorithm on TCP connections.
1764                  * Connections accepted from this listener will
1765                  * inherit the listener options.
1766                  */
1767 
1768                 /* LINTED pointer alignment */
1769                 opt = (struct opthdr *)reqbuf;
1770                 opt->level = IPPROTO_TCP;
1771                 opt->name = TCP_NODELAY;
1772                 opt->len = sizeof (int);
1773 
1774                 /* LINTED pointer alignment */
1775                 *(int *)((char *)opt + sizeof (*opt)) = 1;
1776 
1777                 req.flags = T_NEGOTIATE;
1778                 req.opt.len = sizeof (*opt) + opt->len;
1779                 req.opt.buf = (char *)opt;
1780                 resp.flags = 0;
1781                 resp.opt.buf = reqbuf;
1782                 resp.opt.maxlen = sizeof (reqbuf);
1783 
1784                 if (t_optmgmt(fd, &req, &resp) < 0 ||
1785                     resp.flags != T_SUCCESS) {
1786                         syslog(LOG_ERR, "couldn't set NODELAY option for "
1787                             "proto %s: t_errno = %d, %m", nconf->nc_proto,
1788                             t_errno);
1789                 }
1790         }
1791 
1792         return (fd);
1793 }
1794 
1795 
1796 /* ARGSUSED */
1797 static int
1798 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
1799                 struct netconfig **retnconf)
1800 {
1801         struct netconfig *nconf;
1802         NCONF_HANDLE *nc;
1803         struct nd_hostserv hs;
1804 
1805         hs.h_host = HOST_SELF;
1806         hs.h_serv = RDC_SERVICE;        /* serv_name_to_port_name(serv); */
1807 
1808         if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1809                 syslog(LOG_ERR, "setnetconfig failed: %m");
1810                 return (-1);
1811         }
1812         while (nconf = getnetconfig(nc)) {
1813                 if (OK_TPI_TYPE(nconf) &&
1814                     strcmp(nconf->nc_device, provider) == 0) {
1815                         *retnconf = nconf;
1816                         return (rdcd_bindit(nconf, addr, &hs, listen_backlog));
1817                 }
1818         }
1819         (void) endnetconfig(nc);
1820         if ((Is_ipv6present() && (strcmp(provider, "/dev/tcp6") == 0)) ||
1821             (!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
1822                 syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
1823                     provider);
1824         return (-1);
1825 }
1826 
1827 
1828 /*
1829  * For listen fd's index is always less than end_listen_fds.
1830  * It's value is equal to the number of open file descriptors after the
1831  * last listen end point was opened but before any connection was accepted.
1832  */
1833 static int
1834 is_listen_fd_index(int index)
1835 {
1836         return (index < end_listen_fds);
1837 }
1838 
1839 
1840 /*
1841  * Create an address mask appropriate for the transport.
1842  * The mask is used to obtain the host-specific part of
1843  * a network address when comparing addresses.
1844  * For an internet address the host-specific part is just
1845  * the 32 bit IP address and this part of the mask is set
1846  * to all-ones. The port number part of the mask is zeroes.
1847  */
1848 static int
1849 set_addrmask(int fd, struct netconfig *nconf, struct netbuf *mask)
1850 {
1851         struct t_info info;
1852 
1853         /*
1854          * Find the size of the address we need to mask.
1855          */
1856         if (t_getinfo(fd, &info) < 0) {
1857                 t_error("t_getinfo");
1858                 return (-1);
1859         }
1860         mask->len = mask->maxlen = info.addr;
1861         if (info.addr <= 0) {
1862                 syslog(LOG_ERR, "set_addrmask: address size: %ld", info.addr);
1863                 return (-1);
1864         }
1865 
1866         mask->buf = (char *)malloc(mask->len);
1867         if (mask->buf == NULL) {
1868                 syslog(LOG_ERR, "set_addrmask: no memory");
1869                 return (-1);
1870         }
1871         (void) memset(mask->buf, 0, mask->len);   /* reset all mask bits */
1872 
1873         if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
1874                 /*
1875                  * Set the mask so that the port is ignored.
1876                  */
1877                 /* LINTED pointer alignment */
1878                 ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
1879                     (in_addr_t)~0;
1880                 /* LINTED pointer alignment */
1881                 ((struct sockaddr_in *)mask->buf)->sin_family = (sa_family_t)~0;
1882         }
1883 #ifdef NC_INET6
1884         else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
1885                 /* LINTED pointer alignment */
1886                 (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
1887                     (uchar_t)~0, sizeof (struct in6_addr));
1888                 /* LINTED pointer alignment */
1889                 ((struct sockaddr_in6 *)mask->buf)->sin6_family =
1890                     (sa_family_t)~0;
1891         }
1892 #endif
1893         else {
1894                 /*
1895                  * Set all mask bits.
1896                  */
1897                 (void) memset(mask->buf, (uchar_t)~0, mask->len);
1898         }
1899         return (0);
1900 }
1901 
1902 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
1903 
1904 static int
1905 sndrsvcpool(int maxservers)
1906 {
1907         struct svcpool_args npa;
1908 
1909         npa.id = RDC_SVCPOOL_ID;
1910         npa.maxthreads = maxservers;
1911         npa.redline = 0;
1912         npa.qsize = 0;
1913         npa.timeout = 0;
1914         npa.stksize = 0;
1915         npa.max_same_xprt = 0;
1916         return (sndrsys(RDC_POOL_CREATE, &npa));
1917 }
1918 
1919 
1920 /*
1921  * The following stolen from cmd/fs.d/nfs/lib/thrpool.c
1922  */
1923 
1924 #include <thread.h>
1925 
1926 /*
1927  * Thread to call into the kernel and do work on behalf of SNDR/ncall-ip.
1928  */
1929 static void *
1930 svcstart(void *arg)
1931 {
1932         int id = (int)arg;
1933         int err;
1934 
1935         while ((err = sndrsys(RDC_POOL_RUN, &id)) != 0) {
1936                 /*
1937                  * Interrupted by a signal while in the kernel.
1938                  * this process is still alive, try again.
1939                  */
1940                 if (err == EINTR)
1941                         continue;
1942                 else
1943                         break;
1944         }
1945 
1946         /*
1947          * If we weren't interrupted by a signal, but did
1948          * return from the kernel, this thread's work is done,
1949          * and it should exit.
1950          */
1951         thr_exit(NULL);
1952         return (NULL);
1953 }
1954 
1955 /*
1956  * User-space "creator" thread. This thread blocks in the kernel
1957  * until new worker threads need to be created for the service
1958  * pool. On return to userspace, if there is no error, create a
1959  * new thread for the service pool.
1960  */
1961 static void *
1962 svcblock(void *arg)
1963 {
1964         int id = (int)arg;
1965 
1966         /* CONSTCOND */
1967         while (1) {
1968                 thread_t tid;
1969                 int err;
1970 
1971                 /*
1972                  * Call into the kernel, and hang out there
1973                  * until a thread needs to be created.
1974                  */
1975                 if (err = sndrsys(RDC_POOL_WAIT, &id)) {
1976                         if (err == ECANCELED || err == EBUSY)
1977                                 /*
1978                                  * If we get back ECANCELED, the service
1979                                  * pool is exiting, and we may as well
1980                                  * clean up this thread. If EBUSY is
1981                                  * returned, there's already a thread
1982                                  * looping on this pool, so we should
1983                                  * give up.
1984                                  */
1985                                 break;
1986                         else
1987                                 continue;
1988                 }
1989 
1990                 (void) thr_create(NULL, NULL, svcstart, (void *)id,
1991                     THR_BOUND | THR_DETACHED, &tid);
1992         }
1993 
1994         thr_exit(NULL);
1995         return (NULL);
1996 }
1997 
1998 static int
1999 svcwait(int id)
2000 {
2001         thread_t tid;
2002 
2003         /*
2004          * Create a bound thread to wait for kernel LWPs that
2005          * need to be created.
2006          */
2007         if (thr_create(NULL, NULL, svcblock, (void *)id,
2008             THR_BOUND | THR_DETACHED, &tid))
2009                 return (1);
2010 
2011         return (0);
2012 }
2013 #endif /* Solaris 9+ */