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