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
|