Print this page
4953763 Need way to configure NFS window sizes without changing system wide defaults
6216670 NFS server needs a bigger transmit buffer


   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"


  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         }


 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 */


 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 


 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;


 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                         /*


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




   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 2009 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 #define PORTMAP
  31 
  32 #include <tiuser.h>
  33 #include <fcntl.h>
  34 #include <netconfig.h>
  35 #include <stropts.h>
  36 #include <errno.h>
  37 #include <syslog.h>
  38 #include <rpc/rpc.h>
  39 #include <rpc/pmap_prot.h>
  40 #include <sys/time.h>
  41 #include <sys/resource.h>
  42 #include <signal.h>
  43 #include <netdir.h>
  44 #include <unistd.h>
  45 #include <string.h>
  46 #include <netinet/tcp.h>
  47 #include <malloc.h>
  48 #include <stdlib.h>
  49 #include "nfs_tbind.h"


  84         struct conn_ind *conn_next;
  85         struct conn_ind *conn_prev;
  86         struct t_call   *conn_call;
  87 };
  88 
  89 struct conn_entry {
  90         bool_t                  closing;
  91         struct netconfig        nc;
  92 };
  93 
  94 /*
  95  * this file contains transport routines common to nfsd and lockd
  96  */
  97 static  int     nofile_increase(int);
  98 static  int     reuseaddr(int);
  99 static  int     recvucred(int);
 100 static  int     anonmlp(int);
 101 static  void    add_to_poll_list(int, struct netconfig *);
 102 static  char    *serv_name_to_port_name(char *);
 103 static  int     bind_to_proto(char *, char *, struct netbuf **,
 104                                 struct netconfig **, int, int);
 105 static  int     bind_to_provider(char *, char *, struct netbuf **,
 106                                 struct netconfig **, int, int);
 107 static  void    conn_close_oldest(void);
 108 static  boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
 109 static  void    cots_listen_event(int, int);
 110 static  int     discon_get(int, struct netconfig *, struct conn_ind **);
 111 static  int     do_poll_clts_action(int, int);
 112 static  int     do_poll_cots_action(int, int);
 113 static  void    remove_from_poll_list(int);
 114 static  int     set_addrmask(int, struct netconfig *, struct netbuf *);
 115 static  int     is_listen_fd_index(int);
 116 
 117 static  struct pollfd *poll_array;
 118 static  struct conn_entry *conn_polled;
 119 static  int     num_conns;              /* Current number of connections */
 120 int             (*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
 121                 struct netbuf *);
 122 static int      setopt(int fd, int level, int name, int value);
 123 
 124 extern bool_t __pmap_set(const rpcprog_t program, const rpcvers_t version,
 125     const struct netconfig *nconf, const struct netbuf *address);
 126 
 127 /*
 128  * Called to create and prepare a transport descriptor for in-kernel
 129  * RPC service.
 130  * Returns -1 on failure and a valid descriptor on success.
 131  */
 132 int
 133 nfslib_transport_open(struct netconfig *nconf)
 134 {
 135         int fd;
 136         struct strioctl strioc;
 137 
 138         if ((nconf == (struct netconfig *)NULL) ||
 139             (nconf->nc_device == (char *)NULL)) {
 140                 syslog(LOG_ERR, "no netconfig device");
 141                 return (-1);
 142         }


 222         }
 223 
 224         if (limit > 0)
 225                 rl.rlim_cur = limit;
 226         else
 227                 rl.rlim_cur += NOFILE_INC_SIZE;
 228 
 229         if (rl.rlim_cur > rl.rlim_max &&
 230             rl.rlim_max != RLIM_INFINITY)
 231                 rl.rlim_max = rl.rlim_cur;
 232 
 233         if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
 234                 syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m",
 235                     rl.rlim_cur);
 236                 return (-1);
 237         }
 238 
 239         return (0);
 240 }
 241 
 242 static int
 243 nfslib_set_sockbuf(int fd, int which, int val)
 244 {
 245         if ((which != SO_RCVBUF) && (which != SO_SNDBUF))
 246                 return (-1);
 247 
 248         syslog(LOG_DEBUG, "Set %s option to %d",
 249             ((which == SO_RCVBUF) ? "SO_RCVBUF" : "SO_SNDBUF"), val);
 250 
 251         if (setopt(fd, SOL_SOCKET, which, val) < 0) {
 252                 syslog(LOG_ERR, "couldn't set %s to %d - t_errno = %d",
 253                     ((which == SO_RCVBUF) ? "SO_RCVBUF" : "SO_SNDBUF"),
 254                     val, t_errno);
 255                 syslog(LOG_ERR, "Check and increase system-wide tcp_max_buf");
 256                 return (-1);
 257         }
 258         return (0);
 259 }
 260 
 261 int
 262 nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
 263         struct nd_hostserv *hs, int backlog, int sndbufsz, int rcvbufsz)
 264 {
 265         int fd;
 266         struct t_bind  *ntb;
 267         struct t_bind tb;
 268         struct nd_addrlist *addrlist;
 269         struct t_optmgmt req, resp;
 270         struct opthdr *opt;
 271         char reqbuf[128];
 272         bool_t use_any = FALSE;
 273         bool_t gzone = TRUE;
 274 
 275         if ((fd = nfslib_transport_open(nconf)) == -1) {
 276                 syslog(LOG_ERR, "cannot establish transport service over %s",
 277                     nconf->nc_device);
 278                 return (-1);
 279         }
 280 
 281         addrlist = (struct nd_addrlist *)NULL;
 282 
 283         /* nfs4_callback service does not used a fieed port number */


 403                 opt->level = IPPROTO_TCP;
 404                 opt->name = TCP_NODELAY;
 405                 opt->len = sizeof (int);
 406 
 407                 /* LINTED pointer alignment */
 408                 *(int *)((char *)opt + sizeof (*opt)) = 1;
 409 
 410                 req.flags = T_NEGOTIATE;
 411                 req.opt.len = sizeof (*opt) + opt->len;
 412                 req.opt.buf = (char *)opt;
 413                 resp.flags = 0;
 414                 resp.opt.buf = reqbuf;
 415                 resp.opt.maxlen = sizeof (reqbuf);
 416 
 417                 if (t_optmgmt(fd, &req, &resp) < 0 ||
 418                     resp.flags != T_SUCCESS) {
 419                         syslog(LOG_ERR,
 420         "couldn't set NODELAY option for proto %s: t_errno = %d, %m",
 421                             nconf->nc_proto, t_errno);
 422                 }
 423 
 424                 if (sndbufsz > 0)
 425                         (void) nfslib_set_sockbuf(fd, SO_SNDBUF, sndbufsz);
 426                 if (rcvbufsz > 0)
 427                         (void) nfslib_set_sockbuf(fd, SO_RCVBUF, rcvbufsz);
 428         }
 429 
 430         return (fd);
 431 }
 432 
 433 static int
 434 setopt(int fd, int level, int name, int value)
 435 {
 436         struct t_optmgmt req, resp;
 437         struct {
 438                 struct opthdr opt;
 439                 int value;
 440         } reqbuf;
 441 
 442         reqbuf.opt.level = level;
 443         reqbuf.opt.name = name;
 444         reqbuf.opt.len = sizeof (int);
 445 
 446         reqbuf.value = value;
 447 


 483 {
 484         int error;
 485 
 486         /*
 487          * Save the error code across syslog(), just in case syslog()
 488          * gets its own error and, therefore, overwrites errno.
 489          */
 490         error = errno;
 491         if (t_errno == TSYSERR) {
 492                 syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
 493                     tli_name, fd, nconf->nc_proto);
 494         } else {
 495                 syslog(LOG_ERR,
 496                     "%s(file descriptor %d/transport %s) TLI error %d",
 497                     tli_name, fd, nconf->nc_proto, t_errno);
 498         }
 499         errno = error;
 500 }
 501 
 502 /*
 503  * Called to set up service over a particular transport also
 504  * set send and receive buffer size for transport connection.
 505  */
 506 void
 507 do_one_setbuf(char *provider, NETSELDECL(proto), struct protob *protobp0,
 508         int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap,
 509         int sndbufsz, int rcvbufsz)
 510 {
 511         register int sock;
 512         struct protob *protobp;
 513         struct netbuf *retaddr;
 514         struct netconfig *retnconf;
 515         struct netbuf addrmask;
 516         int vers;
 517         int err;
 518         int l;
 519 
 520         if (provider)
 521                 sock = bind_to_provider(provider, protobp0->serv, &retaddr,
 522                     &retnconf, sndbufsz, rcvbufsz);
 523         else
 524                 sock = bind_to_proto(proto, protobp0->serv, &retaddr,
 525                     &retnconf, sndbufsz, rcvbufsz);
 526 
 527         if (sock == -1) {
 528                 (void) syslog(LOG_ERR,
 529         "Cannot establish %s service over %s: transport setup problem.",
 530                     protobp0->serv, provider ? provider : proto);
 531                 return;
 532         }
 533 
 534         if (set_addrmask(sock, retnconf, &addrmask) < 0) {
 535                 (void) syslog(LOG_ERR,
 536                     "Cannot set address mask for %s", retnconf->nc_netid);
 537                 return;
 538         }
 539 
 540         /*
 541          * Register all versions of the programs in the protocol block list.
 542          */
 543         l = strlen(NC_UDP);
 544         for (protobp = protobp0; protobp; protobp = protobp->next) {
 545                 for (vers = protobp->versmin; vers <= protobp->versmax;


 590                         err = (*Mysvc4)(sock, &addrmask, retnconf,
 591                             NFS4_SETPORT|NFS4_KRPC_START, retaddr);
 592                 else
 593                         err = (*svc)(sock, addrmask, retnconf);
 594 
 595                 if (err < 0) {
 596                         (void) syslog(LOG_ERR,
 597                             "Cannot establish %s service over <file desc."
 598                             " %d, protocol %s> : %m. Exiting",
 599                             protobp0->serv, sock, retnconf->nc_proto);
 600                         exit(1);
 601                 }
 602         }
 603 
 604         /*
 605          * We successfully set up the server over this transport.
 606          * Add this descriptor to the one being polled on.
 607          */
 608         add_to_poll_list(sock, retnconf);
 609 }
 610 
 611 /*
 612  * Set up the NFS service over all the available transports and
 613  * also set send and receive buffer size for transport connection.
 614  * Returns -1 for failure, 0 for success.
 615  */
 616 int
 617 do_all_setbuf(struct protob *protobp,
 618         int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap,
 619         int sndbufsz, int rcvbufsz)
 620 {
 621         struct netconfig *nconf;
 622         NCONF_HANDLE *nc;
 623         int l;
 624 
 625         if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
 626                 syslog(LOG_ERR, "setnetconfig failed: %m");
 627                 return (-1);
 628         }
 629         l = strlen(NC_UDP);
 630         while (nconf = getnetconfig(nc)) {
 631                 if ((nconf->nc_flag & NC_VISIBLE) &&
 632                     strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
 633                     OK_TPI_TYPE(nconf) &&
 634                     (protobp->program != NFS4_CALLBACK ||
 635                     strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
 636                         do_one_setbuf(nconf->nc_device, nconf->nc_proto,
 637                             protobp, svc, use_pmap, sndbufsz, rcvbufsz);
 638         }
 639         (void) endnetconfig(nc);
 640         return (0);
 641 }
 642 
 643 /*
 644  * Called to set up service over a particular transport.
 645  */
 646 void
 647 do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
 648         int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
 649 {
 650         do_one_setbuf(provider, proto, protobp0, svc, use_pmap, 0, 0);
 651 }
 652 
 653 /*
 654  * Set up the NFS service over all the available transports.
 655  * Returns -1 for failure, 0 for success.
 656  */
 657 int
 658 do_all(struct protob *protobp,
 659         int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
 660 {
 661         return (do_all_setbuf(protobp, svc, use_pmap, 0, 0));
 662 }
 663 
 664 /*
 665  * poll on the open transport descriptors for events and errors.
 666  */
 667 void
 668 poll_for_action(void)
 669 {
 670         int nfds;
 671         int i;
 672 
 673         /*
 674          * Keep polling until all transports have been closed. When this
 675          * happens, we return.
 676          */
 677         while ((int)num_fds > 0) {
 678                 nfds = poll(poll_array, num_fds, INFTIM);
 679                 switch (nfds) {
 680                 case 0:
 681                         continue;
 682 
 683                 case -1:
 684                         /*


1609 static char *
1610 serv_name_to_port_name(char *name)
1611 {
1612         /*
1613          * Map service names (used primarily in logging) to
1614          * RPC port names (used by netdir_*() routines).
1615          */
1616         if (strcmp(name, "NFS") == 0) {
1617                 return ("nfs");
1618         } else if (strcmp(name, "NLM") == 0) {
1619                 return ("lockd");
1620         } else if (strcmp(name, "NFS4_CALLBACK") == 0) {
1621                 return ("nfs4_callback");
1622         }
1623 
1624         return ("unrecognized");
1625 }
1626 
1627 static int
1628 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
1629                 struct netconfig **retnconf, int sndbufsz, int rcvbufsz)
1630 {
1631         struct netconfig *nconf;
1632         NCONF_HANDLE *nc;
1633         struct nd_hostserv hs;
1634 
1635         hs.h_host = HOST_SELF;
1636         hs.h_serv = serv_name_to_port_name(serv);
1637 
1638         if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1639                 syslog(LOG_ERR, "setnetconfig failed: %m");
1640                 return (-1);
1641         }
1642         while (nconf = getnetconfig(nc)) {
1643                 if (OK_TPI_TYPE(nconf) &&
1644                     strcmp(nconf->nc_device, provider) == 0) {
1645                         *retnconf = nconf;
1646                         return (nfslib_bindit(nconf, addr, &hs,
1647                             listen_backlog, sndbufsz, rcvbufsz));
1648                 }
1649         }
1650         (void) endnetconfig(nc);
1651 
1652         syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
1653             provider);
1654         return (-1);
1655 }
1656 
1657 static int
1658 bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
1659                 struct netconfig **retnconf, int sndbufsz, int rcvbufsz)
1660 {
1661         struct netconfig *nconf;
1662         NCONF_HANDLE *nc = NULL;
1663         struct nd_hostserv hs;
1664 
1665         hs.h_host = HOST_SELF;
1666         hs.h_serv = serv_name_to_port_name(serv);
1667 
1668         if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1669                 syslog(LOG_ERR, "setnetconfig failed: %m");
1670                 return (-1);
1671         }
1672         while (nconf = getnetconfig(nc)) {
1673                 if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
1674                         *retnconf = nconf;
1675                         return (nfslib_bindit(nconf, addr, &hs,
1676                             listen_backlog, sndbufsz, rcvbufsz));
1677                 }
1678         }
1679         (void) endnetconfig(nc);
1680 
1681         syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",
1682             proto);
1683         return (-1);
1684 }
1685 
1686 #include <netinet/in.h>
1687 
1688 /*
1689  * Create an address mask appropriate for the transport.
1690  * The mask is used to obtain the host-specific part of
1691  * a network address when comparing addresses.
1692  * For an internet address the host-specific part is just
1693  * the 32 bit IP address and this part of the mask is set
1694  * to all-ones. The port number part of the mask is zeroes.
1695  */
1696 static int