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