--- old/exception_lists/packaging	Mon Jul 17 16:15:15 2017
+++ new/exception_lists/packaging	Mon Jul 17 16:15:15 2017
@@ -629,6 +629,7 @@
 usr/lib/fs/nfs/libshare_nfs.so
 usr/lib/fs/nfs/amd64/libshare_nfs.so		i386
 usr/lib/fs/nfs/sparcv9/libshare_nfs.so		sparc
+usr/lib/fs/nfs/test_svc_tp_create
 usr/lib/fs/smb/libshare_smb.so
 usr/lib/fs/smb/amd64/libshare_smb.so		i386
 usr/lib/fs/smb/sparcv9/libshare_smb.so		sparc
--- old/usr/src/cmd/fs.d/nfs/Makefile	Mon Jul 17 16:15:15 2017
+++ new/usr/src/cmd/fs.d/nfs/Makefile	Mon Jul 17 16:15:15 2017
@@ -33,7 +33,7 @@
 
 SUBDIR1=	exportfs nfsd rquotad \
 		statd nfsstat mountd dfshares \
-		nfsfind nfs4cbd share
+		nfsfind nfs4cbd share tests
 
 # These do "make catalog"
 SUBDIR2=	clear_locks lockd umount showmount \
--- old/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Mon Jul 17 16:15:16 2017
+++ new/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Mon Jul 17 16:15:16 2017
@@ -20,8 +20,9 @@
  */
 
 /*
- * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -117,10 +118,12 @@
 static int newopts(char *);
 static tsol_tpent_t *get_client_template(struct sockaddr *);
 
+static int debug;
 static int verbose;
 static int rejecting;
 static int mount_vers_min = MOUNTVERS;
 static int mount_vers_max = MOUNTVERS3;
+static int mountd_port = 0;
 
 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
 
@@ -362,6 +365,82 @@
 	return (0);
 }
 
+/*
+ * This function is called for each configured network type to
+ * bind and register our RPC service programs.
+ *
+ * On TCP or UDP, we may want to bind MOUNTPROG on a specific port
+ * (when mountd_port is specified) in which case we'll use the
+ * variant of svc_tp_create() that lets us pass a bind address.
+ */
+static void
+md_svc_tp_create(struct netconfig *nconf)
+{
+	char port_str[8];
+	struct nd_hostserv hs;
+	struct nd_addrlist *al = NULL;
+	SVCXPRT *xprt = NULL;
+	rpcvers_t vers;
+
+	vers = mount_vers_max;
+
+	/*
+	 * If mountd_port is set and this is an inet transport,
+	 * bind this service on the specified port.  The TLI way
+	 * to create such a bind address is netdir_getbyname()
+	 * with the special "host" HOST_SELF_BIND.  This builds
+	 * an all-zeros IP address with the specified port.
+	 */
+	if (mountd_port != 0 &&
+	    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
+	    strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
+		int err;
+
+		snprintf(port_str, sizeof (port_str), "%u",
+		    (unsigned short)mountd_port);
+
+		hs.h_host = HOST_SELF_BIND;
+		hs.h_serv = port_str;
+		err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
+		if (err == 0 && al != NULL) {
+			xprt = svc_tp_create_addr(mnt, MOUNTPROG, vers,
+			    nconf, al->n_addrs);
+			netdir_free(al, ND_ADDRLIST);
+		}
+		if (xprt == NULL) {
+			syslog(LOG_ERR, "mountd: unable to create "
+			    "(MOUNTD,%d) on transport %s (port %d)",
+			    vers, nconf->nc_netid, mountd_port);
+		}
+		/* fall-back to default bind */
+	}
+	if (xprt == NULL) {
+		/*
+		 * Had mountd_port=0, or non-inet transport,
+		 * or the bind to a specific port failed.
+		 * Do a default bind.
+		 */
+		xprt = svc_tp_create(mnt, MOUNTPROG, vers, nconf);
+	}
+	if (xprt == NULL) {
+		syslog(LOG_ERR, "mountd: unable to create "
+		    "(MOUNTD,%d) on transport %s",
+		    vers, nconf->nc_netid);
+		return;
+	}
+
+	/*
+	 * Register additional versions on this transport.
+	 */
+	while (--vers >= mount_vers_min) {
+		if (!svc_reg(xprt, MOUNTPROG, vers, mnt, nconf)) {
+			(void) syslog(LOG_ERR, "mountd: "
+			    "failed to register vers %d on %s",
+			    vers, nconf->nc_netid);
+		}
+	}
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -379,6 +458,8 @@
 	int listen_backlog = 0;
 	int max_threads = 0;
 	int tmp;
+	struct netconfig *nconf;
+	NCONF_HANDLE *nc;
 
 	int	pipe_fd = -1;
 
@@ -398,6 +479,7 @@
 	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
 	    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
+	    PRIV_NET_PRIVADDR,
 	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
 		(void) fprintf(stderr,
 		    "%s: must be run with sufficient privileges\n",
@@ -422,8 +504,18 @@
 		    "failed, using default value");
 	}
 
-	while ((c = getopt(argc, argv, "vrm:")) != EOF) {
+	ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
+	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
+	if (ret != SA_OK) {
+		syslog(LOG_ERR, "Reading of mountd_port from SMF "
+		    "failed, using default value");
+	}
+
+	while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
 		switch (c) {
+		case 'd':
+			debug++;
+			break;
 		case 'v':
 			verbose++;
 			break;
@@ -439,6 +531,15 @@
 			}
 			max_threads = tmp;
 			break;
+		case 'p':
+			if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
+			    tmp > UINT16_MAX) {
+				(void) fprintf(stderr, "%s: invalid port "
+				    "number\n", argv[0]);
+				break;
+			}
+			mountd_port = tmp;
+			break;
 		default:
 			fprintf(stderr, "usage: mountd [-v] [-r]\n");
 			exit(1);
@@ -488,6 +589,8 @@
 	 * even though we may get versions > MOUNTVERS3, we still need
 	 * to start nfsauth service, so continue on regardless of values.
 	 */
+	if (mount_vers_max > MOUNTVERS3)
+		mount_vers_max = MOUNTVERS3;
 	if (mount_vers_min > mount_vers_max) {
 		fprintf(stderr, "server_versmin > server_versmax\n");
 		mount_vers_max = mount_vers_min;
@@ -508,7 +611,8 @@
 	/* Don't drop core if the NFS module isn't loaded. */
 	(void) signal(SIGSYS, SIG_IGN);
 
-	pipe_fd = daemonize_init();
+	if (!debug)
+		pipe_fd = daemonize_init();
 
 	/*
 	 * If we coredump it'll be in /core
@@ -516,7 +620,8 @@
 	if (chdir("/") < 0)
 		fprintf(stderr, "chdir /: %s\n", strerror(errno));
 
-	openlog("mountd", LOG_PID, LOG_DAEMON);
+	if (!debug)
+		openlog("mountd", LOG_PID, LOG_DAEMON);
 
 	/*
 	 * establish our lock on the lock file and write our pid to it.
@@ -601,6 +706,11 @@
 		exit(1);
 	}
 
+	if (mountd_port < 0 || mountd_port > UINT16_MAX) {
+		fprintf(stderr, "unable to use specified port\n");
+		exit(1);
+	}
+
 	/*
 	 * Make sure to unregister any previous versions in case the
 	 * user is reconfiguring the server in interesting ways.
@@ -645,49 +755,28 @@
 	}
 
 	/*
-	 * Create datagram and connection oriented services
+	 * Enumerate network transports and create service listeners
+	 * as appropriate for each.
 	 */
-	if (mount_vers_max >= MOUNTVERS) {
-		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
-			fprintf(stderr,
-			    "couldn't register datagram_v MOUNTVERS\n");
-			exit(1);
-		}
-		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
-			fprintf(stderr,
-			    "couldn't register circuit_v MOUNTVERS\n");
-			exit(1);
-		}
+	if ((nc = setnetconfig()) == NULL) {
+		syslog(LOG_ERR, "setnetconfig failed: %m");
+		return (-1);
 	}
+	while ((nconf = getnetconfig(nc)) != NULL) {
+		/*
+		 * Skip things like tpi_raw, invisible...
+		 */
+		if ((nconf->nc_flag & NC_VISIBLE) == 0)
+			continue;
+		if (nconf->nc_semantics != NC_TPI_CLTS &&
+		    nconf->nc_semantics != NC_TPI_COTS &&
+		    nconf->nc_semantics != NC_TPI_COTS_ORD)
+			continue;
 
-	if (mount_vers_max >= MOUNTVERS_POSIX) {
-		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
-		    "datagram_v") == 0) {
-			fprintf(stderr,
-			    "couldn't register datagram_v MOUNTVERS_POSIX\n");
-			exit(1);
-		}
-		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
-		    "circuit_v") == 0) {
-			fprintf(stderr,
-			    "couldn't register circuit_v MOUNTVERS_POSIX\n");
-			exit(1);
-		}
+		md_svc_tp_create(nconf);
 	}
+	(void) endnetconfig(nc);
 
-	if (mount_vers_max >= MOUNTVERS3) {
-		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
-			fprintf(stderr,
-			    "couldn't register datagram_v MOUNTVERS3\n");
-			exit(1);
-		}
-		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
-			fprintf(stderr,
-			    "couldn't register circuit_v MOUNTVERS3\n");
-			exit(1);
-		}
-	}
-
 	/*
 	 * Start serving
 	 */
--- old/usr/src/cmd/fs.d/nfs/statd/Makefile	Mon Jul 17 16:15:16 2017
+++ new/usr/src/cmd/fs.d/nfs/statd/Makefile	Mon Jul 17 16:15:16 2017
@@ -28,6 +28,8 @@
 # Copyright 1990-2003 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+# Copyright (c) 2016 by Delphix. All rights reserved.
+#
 
 FSTYPE=		nfs
 TYPEPROG=	statd
@@ -37,15 +39,18 @@
 CPPFLAGS +=     -D_REENTRANT -DSUN_THREADS
 
 CERRWARN +=	-_gcc=-Wno-unused-variable
+CERRWARN +=	-_gcc=-Wno-switch
 CERRWARN +=	-_gcc=-Wno-parentheses
 CERRWARN +=	-_gcc=-Wno-uninitialized
 
 LOCAL=		sm_svc.o sm_proc.o sm_statd.o
-OBJS= 		$(LOCAL) selfcheck.o daemon.o
+OBJS=		$(LOCAL) selfcheck.o daemon.o smfcfg.o
 
-SRCS=		$(LOCAL:%.o=%.c) ../lib/selfcheck.c ../lib/daemon.c
+SRCS=		$(LOCAL:%.o=%.c) ../lib/selfcheck.c ../lib/daemon.c \
+		../lib/smfcfg.c
 
-LDLIBS +=	-lsocket -lrpcsvc -lnsl
+LDLIBS +=	-lsocket -lrpcsvc -lnsl -lscf
+CPPFLAGS +=     -I../lib
 
 $(TYPEPROG):	$(OBJS)
 		$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
@@ -58,6 +63,9 @@
 daemon.o:	../lib/daemon.c
 		$(COMPILE.c) ../lib/daemon.c
 
+smfcfg.o:	../lib/smfcfg.c
+		$(COMPILE.c) ../lib/smfcfg.c
+
 lint:		lint_SRCS
 
 clean:
--- old/usr/src/cmd/fs.d/nfs/statd/sm_svc.c	Mon Jul 17 16:15:16 2017
+++ new/usr/src/cmd/fs.d/nfs/statd/sm_svc.c	Mon Jul 17 16:15:16 2017
@@ -20,8 +20,9 @@
  */
 
 /*
- * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
@@ -37,10 +38,6 @@
  * contributors.
  */
 
-/*
- * Copyright (c) 2012 by Delphix. All rights reserved.
- */
-
 #include <stdio.h>
 #include <stdio_ext.h>
 #include <stdlib.h>
@@ -49,9 +46,11 @@
 #include <string.h>
 #include <syslog.h>
 #include <netconfig.h>
+#include <netdir.h>
 #include <unistd.h>
 #include <netdb.h>
 #include <rpc/rpc.h>
+#include <rpc/svc.h>
 #include <netinet/in.h>
 #include <sys/param.h>
 #include <sys/resource.h>
@@ -69,6 +68,7 @@
 #include <limits.h>
 #include <rpcsvc/daemon_utils.h>
 #include <priv_utils.h>
+#include "smfcfg.h"
 #include "sm_statd.h"
 
 
@@ -99,6 +99,7 @@
 
 int debug;
 int regfiles_only = 0;		/* 1 => use symlinks in statmon, 0 => don't */
+int statd_port = 0;
 char hostname[MAXHOSTNAMELEN];
 
 /*
@@ -457,6 +458,78 @@
 	(void) mutex_unlock(&merges_lock);
 }
 
+/*
+ * This function is called for each configured network type to
+ * bind and register our RPC service programs.
+ *
+ * On TCP or UDP, we may want to bind SM_PROG on a specific port
+ * (when statd_port is specified) in which case we'll use the
+ * variant of svc_tp_create() that lets us pass a bind address.
+ */
+static void
+sm_svc_tp_create(struct netconfig *nconf)
+{
+	char port_str[8];
+	struct nd_hostserv hs;
+	struct nd_addrlist *al = NULL;
+	SVCXPRT *xprt = NULL;
+
+	/*
+	 * If statd_port is set and this is an inet transport,
+	 * bind this service on the specified port.  The TLI way
+	 * to create such a bind address is netdir_getbyname()
+	 * with the special "host" HOST_SELF_BIND.  This builds
+	 * an all-zeros IP address with the specified port.
+	 */
+	if (statd_port != 0 &&
+	    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
+	    strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
+		int err;
+
+		snprintf(port_str, sizeof (port_str), "%u",
+		    (unsigned short)statd_port);
+
+		hs.h_host = HOST_SELF_BIND;
+		hs.h_serv = port_str;
+		err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
+		if (err == 0 && al != NULL) {
+			xprt = svc_tp_create_addr(sm_prog_1, SM_PROG, SM_VERS,
+			    nconf, al->n_addrs);
+			netdir_free(al, ND_ADDRLIST);
+		}
+		if (xprt == NULL) {
+			syslog(LOG_ERR, "statd: unable to create "
+			    "(SM_PROG, SM_VERS) on transport %s (port %d)",
+			    nconf->nc_netid, statd_port);
+		}
+		/* fall-back to default bind */
+	}
+	if (xprt == NULL) {
+		/*
+		 * Had statd_port=0, or non-inet transport,
+		 * or the bind to a specific port failed.
+		 * Do a default bind.
+		 */
+		xprt = svc_tp_create(sm_prog_1, SM_PROG, SM_VERS, nconf);
+	}
+	if (xprt == NULL) {
+		syslog(LOG_ERR, "statd: unable to create "
+		    "(SM_PROG, SM_VERS) for transport %s",
+		    nconf->nc_netid);
+		return;
+	}
+
+	/*
+	 * Also register the NSM_ADDR program on this
+	 * transport handle (same dispatch function).
+	 */
+	if (!svc_reg(xprt, NSM_ADDR_PROGRAM, NSM_ADDR_V1, sm_prog_1, nconf)) {
+		syslog(LOG_ERR, "statd: failed to register "
+		    "(NSM_ADDR_PROGRAM, NSM_ADDR_V1) for "
+		    "netconfig %s", nconf->nc_netid);
+	}
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -468,7 +541,10 @@
 	int mode;
 	int sz;
 	int pipe_fd = -1;
+	int ret;
 	int connmaxrec = RPC_MAXDATASIZE;
+	struct netconfig *nconf;
+	NCONF_HANDLE *nc;
 
 	addrix = 0;
 	pathix = 0;
@@ -477,7 +553,14 @@
 	if (init_hostname() < 0)
 		exit(1);
 
-	while ((c = getopt(argc, argv, "Dd:a:G:p:rU:")) != EOF)
+	ret = nfs_smf_get_iprop("statd_port", &statd_port,
+	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, STATD);
+	if (ret != SA_OK) {
+		syslog(LOG_ERR, "Reading of statd_port from SMF "
+		    "failed, using default value");
+	}
+
+	while ((c = getopt(argc, argv, "Dd:a:G:p:P:rU:")) != EOF)
 		switch (c) {
 		case 'd':
 			(void) sscanf(optarg, "%d", &debug);
@@ -539,15 +622,23 @@
 				pathix++;
 			} else {
 				(void) fprintf(stderr,
-				"statd: -p pathname is too long.\n");
+				    "statd: -p pathname is too long.\n");
 			}
 			break;
+		case 'P':
+			(void) sscanf(optarg, "%d", &statd_port);
+			if (statd_port < 1 || statd_port > UINT16_MAX) {
+				(void) fprintf(stderr,
+				    "statd: -P port invalid.\n");
+				statd_port = 0;
+			}
+			break;
 		case 'r':
 			regfiles_only = 1;
 			break;
 		default:
 			(void) fprintf(stderr,
-			"statd [-d level] [-D]\n");
+			    "statd [-d level] [-D]\n");
 			return (1);
 		}
 
@@ -636,16 +727,29 @@
 		syslog(LOG_INFO, "unable to set maximum RPC record size");
 	}
 
-	if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) {
-		syslog(LOG_ERR, "statd: unable to create (SM_PROG, SM_VERS) "
-		    "for netpath.");
-		exit(1);
+	/*
+	 * Enumerate network transports and create service listeners
+	 * as appropriate for each.
+	 */
+	if ((nc = setnetconfig()) == NULL) {
+		syslog(LOG_ERR, "setnetconfig failed: %m");
+		return (-1);
 	}
+	while ((nconf = getnetconfig(nc)) != NULL) {
 
-	if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) {
-		syslog(LOG_ERR, "statd: unable to create (NSM_ADDR_PROGRAM, "
-		    "NSM_ADDR_V1) for netpath.");
+		/*
+		 * Skip things like tpi_raw, invisible...
+		 */
+		if ((nconf->nc_flag & NC_VISIBLE) == 0)
+			continue;
+		if (nconf->nc_semantics != NC_TPI_CLTS &&
+		    nconf->nc_semantics != NC_TPI_COTS &&
+		    nconf->nc_semantics != NC_TPI_COTS_ORD)
+			continue;
+
+		sm_svc_tp_create(nconf);
 	}
+	(void) endnetconfig(nc);
 
 	/*
 	 * Make sure /var/statmon and any alternate (-p) statmon
@@ -825,7 +929,7 @@
 /*ARGSUSED3*/
 static int
 nftw_owner(const char *path, const struct stat *statp, int info,
-	struct FTW *ftw)
+    struct FTW *ftw)
 {
 	if (!(info == FTW_F || info == FTW_D))
 		return (0);
--- old/usr/src/cmd/fs.d/nfs/svc/server.xml	Mon Jul 17 16:15:17 2017
+++ new/usr/src/cmd/fs.d/nfs/svc/server.xml	Mon Jul 17 16:15:17 2017
@@ -25,6 +25,7 @@
 	Copyright (c) 2012 by Delphix. All rights reserved.
 	Copyright 2014 Nexenta Systems, Inc.  All rights reserved
 	Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
+	Copyright (c) 2012, 2014 by Delphix. All rights reserved.
 
 	NOTE:  This service manifest is not editable; its contents will
 	be overwritten by package or patch operations, including
@@ -152,7 +153,7 @@
 		<propval name='ipf_method' type='astring'
 		    value='/lib/svc/method/nfs-server ipfilter' />
 	</property_group>
- 
+
 	<property_group name='firewall_config' type='com.sun,fw_configuration'>
 		<propval name='policy' type='astring' value='use_global' />
 		<propval name='block_policy' type='astring'
@@ -178,6 +179,7 @@
 	   <propval name='servers' type='integer' value='1024'/>
 	   <propval name='mountd_listen_backlog' type='integer' value='64'/>
 	   <propval name='mountd_max_threads' type='integer' value='16'/>
+	   <propval name='mountd_port' type='integer' value='0'/>
 	 </property_group>
 	</instance>
 
--- old/usr/src/cmd/fs.d/nfs/svc/status.xml	Mon Jul 17 16:15:17 2017
+++ new/usr/src/cmd/fs.d/nfs/svc/status.xml	Mon Jul 17 16:15:17 2017
@@ -33,6 +33,8 @@
 	$SRC/head/rpcsvc/daemon_utils.h and libnsl:open_daemon_lock().
 -->
 
+<!-- Copyright (c) 2016 by Delphix. All rights reserved. -->
+
 <service_bundle type='manifest' name='SUNWnfscr:nfs-status'>
 
 <service
@@ -40,10 +42,6 @@
 	type='service'
 	version='1'>
 
-	<create_default_instance enabled='false' />
-
-	<single_instance />
-
 	<dependency name='network'
 	    grouping='require_any'
 	    restart_on='error'
@@ -89,6 +87,12 @@
 		<propval name='auto_enable' type='boolean' value='true' />
 	</property_group>
 
+	<instance name='default' enabled='false'>
+		<property_group name='nfs-props' type='com.oracle.nfs,props'>
+			<propval name='statd_port' type='integer' value='0'/>
+		</property_group>
+	</instance>
+
 	<stability value='Stable' />
 
 	<template>
--- /dev/null	Mon Jul 17 16:15:17 2017
+++ new/usr/src/cmd/fs.d/nfs/tests/Makefile	Mon Jul 17 16:15:17 2017
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License").  You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/fs.d/nfs/tests/Makefile
+
+FSTYPE=		nfs
+LIBPROG=	test_svc_tp_create
+
+include		../../Makefile.fstype
+
+OBJS=		$(LIBPROG).o
+SRCS=		$(LIBPROG).c
+
+CFLAGS += $(CCVERBOSE)
+
+LDLIBS +=	-lnsl -lsocket
+
+# message catalog
+catalog:
+
+$(LIBPROG):	$(OBJS)
+		$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+		$(POST_PROCESS)
+
+lint:	lint_SRCS
+
+clean:     
+	$(RM) $(LIBPROG).o
--- /dev/null	Mon Jul 17 16:15:17 2017
+++ new/usr/src/cmd/fs.d/nfs/tests/test_svc_tp_create.c	Mon Jul 17 16:15:17 2017
@@ -0,0 +1,332 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <sys/stat.h>
+#include <netconfig.h>
+#include <netdir.h>
+
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <rpcsvc/mount.h>
+
+#include <signal.h>
+#include <locale.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <thread.h>
+#include <assert.h>
+
+#include <limits.h>
+
+#define	TESTPROG	987654
+
+uint32_t test_vers_max = 2;
+uint32_t test_vers_min = 1;
+
+int debug;
+int verbose;
+int testd_port;
+
+static void mysvc(struct svc_req *, SVCXPRT *);
+static void bind2(void);
+
+/*
+ * This function is called for each configured network type to
+ * bind and register our RPC service programs.
+ *
+ * On TCP or UDP, we want to bind TESTPROG on a specific port
+ * (when testd_port is specified) in which case we'll use the
+ * variant of svc_tp_create() that lets us pass a bind address.
+ */
+static void
+test_svc_tp_create(struct netconfig *nconf)
+{
+	char port_str[8];
+	struct nd_hostserv hs;
+	struct nd_addrlist *al = NULL;
+	SVCXPRT *xprt = NULL;
+	rpcvers_t vers;
+
+	vers = test_vers_max;
+
+	/*
+	 * If testd_port is set and this is an inet transport,
+	 * bind this service on the specified port.
+	 */
+	if (testd_port != 0 &&
+	    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
+	    strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
+		int err;
+
+		snprintf(port_str, sizeof (port_str), "%u",
+		    (unsigned short)testd_port);
+
+		hs.h_host = HOST_SELF_BIND;
+		hs.h_serv = port_str;
+		err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
+		if (err == 0 && al != NULL) {
+			xprt = svc_tp_create_addr(mysvc, TESTPROG, vers,
+			    nconf, al->n_addrs);
+			netdir_free(al, ND_ADDRLIST);
+		}
+		if (xprt == NULL) {
+			printf("testd: unable to create "
+			    "(TESTD,%d) on transport %s (port %d)\n",
+			    vers, nconf->nc_netid, testd_port);
+		}
+		/* fall-back to default bind */
+	}
+	if (xprt == NULL) {
+		/*
+		 * Had testd_port=0, or non-inet transport,
+		 * or the bind to a specific port failed.
+		 * Do a default bind.
+		 */
+		xprt = svc_tp_create(mysvc, TESTPROG, vers, nconf);
+	}
+	if (xprt == NULL) {
+		printf("testd: unable to create "
+		    "(TESTD,%d) on transport %s\n",
+		    vers, nconf->nc_netid);
+		return;
+	}
+
+	/*
+	 * Register additional versions on this transport.
+	 */
+	while (--vers >= test_vers_min) {
+		if (!svc_reg(xprt, TESTPROG, vers, mysvc, nconf)) {
+			printf("testd: "
+			    "failed to register vers %d on %s\n",
+			    vers, nconf->nc_netid);
+		}
+	}
+}
+
+static void
+test_svc_unreg(void)
+{
+	rpcvers_t vers;
+
+	for (vers = test_vers_min; vers <= test_vers_max; vers++)
+		svc_unreg(TESTPROG, vers);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int	c;
+	bool_t	exclbind = TRUE;
+	int tmp;
+	struct netconfig *nconf;
+	NCONF_HANDLE *nc;
+
+	while ((c = getopt(argc, argv, "dvp:")) != EOF) {
+		switch (c) {
+		case 'd':
+			debug++;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'p':
+			(void) sscanf(optarg, "%d", &tmp);
+			if (tmp < 1 || tmp > UINT16_MAX) {
+				(void) fprintf(stderr,
+				    "testd: -P port invalid.\n");
+				return (1);
+			}
+			testd_port = tmp;
+			break;
+		default:
+			fprintf(stderr, "usage: testd [-v] [-r]\n");
+			exit(1);
+		}
+	}
+
+	(void) setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN "SYS_TEST"
+#endif
+	(void) textdomain(TEXT_DOMAIN);
+
+	/*
+	 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
+	 * from being hijacked by a bind to a more specific addr.
+	 */
+	if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
+		fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
+	}
+
+	if (testd_port < 0 || testd_port > UINT16_MAX) {
+		fprintf(stderr, "unable to use specified port\n");
+		exit(1);
+	}
+
+	/*
+	 * Make sure to unregister any previous versions in case the
+	 * user is reconfiguring the server in interesting ways.
+	 */
+	test_svc_unreg();
+
+	/*
+	 * Enumerate network transports and create service listeners
+	 * as appropriate for each.
+	 */
+	if ((nc = setnetconfig()) == NULL) {
+		perror("setnetconfig failed");
+		return (-1);
+	}
+	while ((nconf = getnetconfig(nc)) != NULL) {
+		/*
+		 * Skip things like tpi_raw, invisible...
+		 */
+		if ((nconf->nc_flag & NC_VISIBLE) == 0)
+			continue;
+		if (nconf->nc_semantics != NC_TPI_CLTS &&
+		    nconf->nc_semantics != NC_TPI_COTS &&
+		    nconf->nc_semantics != NC_TPI_COTS_ORD)
+			continue;
+
+		test_svc_tp_create(nconf);
+	}
+	(void) endnetconfig(nc);
+
+	/*
+	 * XXX: Normally would call svc_run() here, but
+	 * we just want to check our IP bindings.
+	 */
+	if (testd_port != 0)
+		bind2();
+
+	if (debug) {
+		char sysbuf[100];
+
+		snprintf(sysbuf, sizeof (sysbuf),
+			 "rpcinfo -p |grep %u", TESTPROG);
+		printf("x %s\n", sysbuf);
+		fflush(stdout);
+		system(sysbuf);
+
+		if (testd_port) {
+			snprintf(sysbuf, sizeof (sysbuf),
+				 "netstat -a -f inet -P udp |grep %u", testd_port);
+			printf("x %s\n", sysbuf);
+			fflush(stdout);
+			system(sysbuf);
+
+			snprintf(sysbuf, sizeof (sysbuf),
+				 "netstat -a -f inet -P tcp |grep %u", testd_port);
+			printf("x %s\n", sysbuf);
+			fflush(stdout);
+			system(sysbuf);
+		}
+	}
+
+	/* cleanup */
+	test_svc_unreg();
+
+	printf("%s complete\n", argv[0]);
+	return (0);
+}
+
+/*
+ * Server procedure switch routine
+ */
+static void
+mysvc(struct svc_req *rq, SVCXPRT *xprt)
+{
+
+	switch (rq->rq_proc) {
+	case NULLPROC:
+		errno = 0;
+		(void)svc_sendreply(xprt, xdr_void, (char *)0);
+		return;
+
+	default:
+		svcerr_noproc(xprt);
+		return;
+	}
+}
+
+struct sockaddr_in addr;
+
+/*
+ * The actual test: Try doing a 2nd bind with a specific IP.
+ * The exclusive wildcard bind should prvent this.
+ */
+static void
+bind2(void)
+{
+	int ret;
+	int sock;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(testd_port);
+	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock == -1) {
+		fprintf(stderr, "bind2 socket fail %s\n",
+			strerror(errno));
+		exit(1);
+	}
+
+	ret = bind(sock, (struct sockaddr *)&addr, sizeof (addr));
+	if (ret == -1) {
+		fprintf(stderr, "bind2 bind fail %s (expected) PASS\n", strerror(errno));
+		close(sock);
+		return;
+	}
+
+	printf("Oh no, bind2 worked! test FAILED\n");
+	close(sock);
+	return;
+}
--- old/usr/src/lib/libnsl/common/mapfile-vers	Mon Jul 17 16:15:18 2017
+++ new/usr/src/lib/libnsl/common/mapfile-vers	Mon Jul 17 16:15:18 2017
@@ -20,7 +20,7 @@
 #
 #
 # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
 #
 
 #
@@ -39,6 +39,11 @@
 
 $mapfile_version 2
 
+SYMBOL_VERSION ILLUMOS_0.1 {    # Illumos additions
+    global:
+	svc_tp_create_addr;
+} SUNW_1.10;
+
 SYMBOL_VERSION SUNW_1.10 {	# SunOS 5.11 (Solaris 11)
     global:
 	SUNW_1.10;
--- old/usr/src/lib/libnsl/rpc/svc_generic.c	Mon Jul 17 16:15:18 2017
+++ new/usr/src/lib/libnsl/rpc/svc_generic.c	Mon Jul 17 16:15:18 2017
@@ -20,8 +20,8 @@
  */
 
 /*
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*	Copyright (c) 1988 AT&T */
@@ -87,6 +87,10 @@
 static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
     const struct t_bind *, uint_t, uint_t, boolean_t);
 
+static SVCXPRT *svc_tp_create_bind(void (*dispatch)(),
+    const rpcprog_t, const rpcvers_t,
+    const struct netconfig *, const struct t_bind *);
+
 boolean_t
 is_multilevel(rpcprog_t prognum)
 {
@@ -176,12 +180,51 @@
 /*
  * The high level interface to svc_tli_create().
  * It tries to create a server for "nconf" and registers the service
- * with the rpcbind. It calls svc_tli_create();
+ * with the rpcbind.
  */
 SVCXPRT *
 svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
-			const rpcvers_t versnum, const struct netconfig *nconf)
+    const rpcvers_t versnum, const struct netconfig *nconf)
 {
+	return (svc_tp_create_bind(dispatch, prognum, versnum, nconf, NULL));
+}
+
+/*
+ * svc_tp_create_addr()
+ * Variant of svc_tp_create() that allows specifying just the
+ * the binding address, for convenience.
+ */
+SVCXPRT *
+svc_tp_create_addr(void (*dispatch)(), const rpcprog_t prognum,
+    const rpcvers_t versnum, const struct netconfig *nconf,
+    const struct netbuf *addr)
+{
+	struct t_bind bind;
+	struct t_bind *bindp = NULL;
+
+	if (addr != NULL) {
+
+		bind.addr = *addr;
+		if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET, &bind.qlen)) {
+			syslog(LOG_ERR,
+			    "svc_tp_create: can't get listen backlog");
+			return (NULL);
+		}
+		bindp = &bind;
+	}
+
+	/*
+	 * When bindp == NULL, this is the same as svc_tp_create().
+	 */
+	return (svc_tp_create_bind(dispatch, prognum, versnum,
+	    nconf, bindp));
+}
+
+static SVCXPRT *
+svc_tp_create_bind(void (*dispatch)(), const rpcprog_t prognum,
+    const rpcvers_t versnum, const struct netconfig *nconf,
+    const struct t_bind *bindaddr)
+{
 	SVCXPRT *xprt;
 	boolean_t anon_mlp = B_FALSE;
 
@@ -194,7 +237,8 @@
 	/* Some programs need to allocate MLP for multilevel services */
 	if (is_system_labeled() && is_multilevel(prognum))
 		anon_mlp = B_TRUE;
-	xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp);
+	xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0,
+	    anon_mlp);
 	if (xprt == NULL)
 		return (NULL);
 
@@ -324,7 +368,6 @@
 	}
 
 	switch (state) {
-		bool_t tcp, exclbind;
 	case T_UNBND:
 		/* If this is a labeled system, then ask for an MLP */
 		if (is_system_labeled() &&
@@ -337,32 +380,15 @@
 				    SO_ANON_MLP, 1);
 		}
 
-		/*
-		 * SO_EXCLBIND has the following properties
-		 *    - an fd bound to port P via IPv4 will prevent an IPv6
-		 *    bind to port P (and vice versa)
-		 *    - an fd bound to a wildcard IP address for port P will
-		 *    prevent a more specific IP address bind to port P
-		 *    (see {tcp,udp}.c for details)
-		 *
-		 * We use the latter property to prevent hijacking of RPC
-		 * services that reside at non-privileged ports.
-		 */
-		tcp = nconf ? (strcmp(nconf->nc_proto, NC_TCP) == 0) : 0;
-		if (nconf &&
-		    (tcp || (strcmp(nconf->nc_proto, NC_UDP) == 0)) &&
-		    rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind)) {
-			if (exclbind) {
-				if (__rpc_tli_set_options(fd, SOL_SOCKET,
-				    SO_EXCLBIND, 1) < 0) {
-					syslog(LOG_ERR,
-			    "svc_tli_create: can't set EXCLBIND [netid='%s']",
-					    nconf->nc_netid);
-					goto freedata;
-				}
-			}
-		}
 		if (bindaddr) {
+			/*
+			 * Services that specify a bind address typically
+			 * use a fixed service (IP port) so we need to set
+			 * SO_REUSEADDR to prevent bind errors on restart.
+			 */
+			if (bindaddr->addr.len != 0)
+				(void) __rpc_tli_set_options(fd, SOL_SOCKET,
+				    SO_REUSEADDR, 1);
 			if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
 				char errorstr[100];
 
@@ -403,6 +429,47 @@
 				    errorstr);
 				goto freedata;
 			}
+		}
+
+		/*
+		 * If requested, set SO_EXCLBIND on each binding.
+		 *
+		 * SO_EXCLBIND has the following properties
+		 *    - an fd bound to port P via IPv4 will prevent an IPv6
+		 *    bind to port P (and vice versa)
+		 *    - an fd bound to a wildcard IP address for port P will
+		 *    prevent a more specific IP address bind to port P
+		 *    (see {tcp,udp}.c for details)
+		 *
+		 * We use the latter property to prevent hijacking of RPC
+		 * services that reside at non-privileged ports.
+		 *
+		 * When the bind address is not specified, each bind gets a
+		 * new port number, and (for IP transports) we should set
+		 * the exclusive flag after every IP bind.  That's the
+		 * strcmp nc_proto part of the expression below.
+		 *
+		 * When the bind address IS specified, we need to set the
+		 * exclusive flag only after we've bound both IPv6+IPv4,
+		 * or the IPv4 bind will fail.  Setting the exclusive flag
+		 * after the "tcp" or "udp" transport bind does that.
+		 * That's the strcmp nc_netid part below.
+		 */
+		if (nconf != NULL && ((bindaddr == NULL &&
+		    (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
+		    strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
+		    (strcmp(nconf->nc_netid, "tcp") == 0 ||
+		    strcmp(nconf->nc_netid, "udp") == 0))) {
+			bool_t exclbind = FALSE;
+			(void) rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind);
+			if (exclbind &&
+			    __rpc_tli_set_options(fd, SOL_SOCKET,
+			    SO_EXCLBIND, 1) < 0) {
+				syslog(LOG_ERR,
+			    "svc_tli_create: can't set EXCLBIND [netid='%s']",
+				    nconf->nc_netid);
+				goto freedata;
+			}
 		}
 
 		/* Enable options of returning the ip's for udp */
--- old/usr/src/lib/libshare/nfs/libshare_nfs.c	Mon Jul 17 16:15:18 2017
+++ new/usr/src/lib/libshare/nfs/libshare_nfs.c	Mon Jul 17 16:15:18 2017
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
  */
 
 /*
@@ -2562,6 +2563,14 @@
 	{"mountd_max_threads",
 	    "mountd_max_threads", PROTO_OPT_MOUNTD_MAX_THREADS,
 	    OPT_TYPE_NUMBER, 16, SVC_NFSD|SVC_MOUNTD, 1, INT32_MAX},
+#define	PROTO_OPT_MOUNTD_PORT			17
+	{"mountd_port",
+	    "mountd_port", PROTO_OPT_MOUNTD_PORT,
+	    OPT_TYPE_NUMBER, 0, SVC_MOUNTD, 1, UINT16_MAX},
+#define	PROTO_OPT_STATD_PORT			18
+	{"statd_port",
+	    "statd_port", PROTO_OPT_STATD_PORT,
+	    OPT_TYPE_NUMBER, 0, SVC_STATD, 1, UINT16_MAX},
 	{NULL}
 };
 
--- old/usr/src/man/man3nsl/Makefile	Mon Jul 17 16:15:19 2017
+++ new/usr/src/man/man3nsl/Makefile	Mon Jul 17 16:15:19 2017
@@ -11,7 +11,7 @@
 
 #
 # Copyright 2011, Richard Lowe
-# Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
 #
 
 include		$(SRC)/Makefile.master
@@ -237,6 +237,7 @@
 		svc_sendreply.3nsl			\
 		svc_tli_create.3nsl			\
 		svc_tp_create.3nsl			\
+		svc_tp_create_addr.3nsl			\
 		svc_unreg.3nsl				\
 		svc_unregister.3nsl			\
 		svc_vc_create.3nsl			\
@@ -462,6 +463,7 @@
 svc_raw_create.3nsl			:= LINKSRC = rpc_svc_create.3nsl
 svc_tli_create.3nsl			:= LINKSRC = rpc_svc_create.3nsl
 svc_tp_create.3nsl			:= LINKSRC = rpc_svc_create.3nsl
+svc_tp_create_addr.3nsl			:= LINKSRC = rpc_svc_create.3nsl
 svc_vc_create.3nsl			:= LINKSRC = rpc_svc_create.3nsl
 
 svcerr_auth.3nsl			:= LINKSRC = rpc_svc_err.3nsl
--- old/usr/src/man/man3nsl/rpc_svc_create.3nsl	Mon Jul 17 16:15:19 2017
+++ new/usr/src/man/man3nsl/rpc_svc_create.3nsl	Mon Jul 17 16:15:19 2017
@@ -1,14 +1,15 @@
 '\" te
-.\" Copyright 2014 Nexenta Systems, Inc.  All Rights Reserved.
+.\" Copyright 2017 Nexenta Systems, Inc.  All Rights Reserved.
 .\"  Copyright 1989 AT&T
 .\" Copyright (C) 2005, Sun Microsystems, Inc. All Rights Reserved.
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH RPC_SVC_CREATE 3NSL "May 18, 2017"
+.TH RPC_SVC_CREATE 3NSL "Jun 19, 2017"
 .SH NAME
 rpc_svc_create, svc_control, svc_create, svc_destroy, svc_dg_create,
-svc_fd_create, svc_raw_create, svc_tli_create, svc_tp_create, svc_vc_create,
+svc_fd_create, svc_raw_create, svc_tli_create, svc_tp_create,
+svc_tp_create_addr, svc_vc_create,
 svc_door_create \- server handle creation routines
 .SH SYNOPSIS
 .LP
@@ -50,7 +51,7 @@
 .LP
 .nf
 \fBSVCXPRT *\fR\fBsvc_tli_create\fR(\fBconst int\fR \fIfildes\fR, \fBconst struct netconfig *\fR\fInetconf\fR,
-     \fBconst struct t_bind *\fR\fIbind_addr\fR, \fBconst uint_t\fR \fIsendsz\fR,
+     \fBconst struct t_bind *\fR\fIbind_info\fR, \fBconst uint_t\fR \fIsendsz\fR,
      \fBconst uint_t\fR \fIrecvsz\fR);
 .fi
 
@@ -63,6 +64,15 @@
 
 .LP
 .nf
+\fBSVCXPRT *\fR\fBsvc_tp_create_addr\fR(\fBconst void (*\fR\fIdispatch\fR)
+     (const struct svc_req *, const SVCXPRT *), \fBconst rpcprog_t\fR \fIprognum\fR,
+     \fBconst rpcvers_t\fR \fIversnum\fR, \fBconst struct netconfig *\fR\fInetconf\fR,
+     \fBconst struct netbuf *\fR\fIbind_addr\fR)
+);
+.fi
+
+.LP
+.nf
 \fBSVCXPRT *\fR\fBsvc_vc_create\fR(\fBconst int\fR \fIfildes\fR, \fBconst uint_t\fR \fIsendsz\fR,
      \fBconst uint_t\fR \fIrecvsz\fR);
 .fi
@@ -88,7 +98,7 @@
 .na
 \fB\fBsvc_control()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 A function to change or retrieve information about a service object. \fIreq\fR
 indicates the type of operation and \fIinfo\fR is a pointer to the information.
 The supported values of \fIreq\fR,  their argument types, and what they do are:
@@ -97,7 +107,7 @@
 .na
 \fB\fBSVCGET_VERSQUIET\fR\fR
 .ad
-.RS 25n
+.RS 10n
 If a request is received for a program number served by this server but the
 version number is outside the range registered with the server, an
 \fBRPC_PROGVERSMISMATCH\fR error will normally be returned.  \fIinfo\fR should
@@ -113,7 +123,7 @@
 .na
 \fB\fBSVCSET_VERSQUIET\fR\fR
 .ad
-.RS 25n
+.RS 10n
 If a request is received for a program number served by this server but the
 version number is outside the range registered with the server, an
 \fBRPC_PROGVERSMISMATCH\fR error will normally be returned.  It is sometimes
@@ -128,7 +138,7 @@
 .na
 \fB\fBSVCGET_XID\fR\fR
 .ad
-.RS 25n
+.RS 10n
 Returns the transaction  \fBID\fR of connection\(mioriented and connectionless
 transport service calls. The transaction  \fBID\fR assists in uniquely
 identifying client requests for a given \fBRPC\fR version, program number,
@@ -148,7 +158,7 @@
 .na
 \fB\fBSVCSET_RECVERRHANDLER\fR\fR
 .ad
-.RS 25n
+.RS 10n
 Attaches or detaches a disconnection handler to the service handle, \fIsvc\fR,
 that will be called when a transport error arrives during the reception of a
 request or when the server is waiting for a request and the connection shuts
@@ -177,7 +187,7 @@
 .na
 \fB\fBSVCGET_RECVERRHANDLER\fR\fR
 .ad
-.RS 25n
+.RS 10n
 Upon successful completion of the \fBSVCGET_RECVERRHANDLER\fR request,
 \fI*info\fR contains the address of the handler for receiving errors. Upon
 failure, \fI*info\fR contains \fINULL\fR.
@@ -188,7 +198,7 @@
 .na
 \fB\fBSVCSET_CONNMAXREC\fR\fR
 .ad
-.RS 25n
+.RS 10n
 Set the maximum record size (in bytes) and enable non-blocking mode for this
 service handle. Value can be set and read for both connection and
 non-connection oriented transports, but is silently ignored for the
@@ -201,7 +211,7 @@
 .na
 \fB\fBSVCGET_CONNMAXREC\fR\fR
 .ad
-.RS 25n
+.RS 10n
 Get the maximum record size for this service handle. Zero means no maximum in
 effect and the connection is in blocking mode. The result is not significant
 for non-connection oriented transports. The \fIinfo\fR argument should be a
@@ -217,7 +227,7 @@
 .na
 \fB\fBsvc_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 \fBsvc_create()\fR creates server handles for all the transports belonging to
 the class \fInettype\fR.
 .sp
@@ -239,7 +249,7 @@
 .na
 \fB\fBsvc_destroy()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 A function macro that destroys the \fBRPC\fR service handle \fIxprt\fR.
 Destruction usually involves deallocation of private data structures, including
 \fIxprt\fR itself.  Use of \fIxprt\fR is undefined after calling this routine.
@@ -250,7 +260,7 @@
 .na
 \fB\fBsvc_dg_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 This routine creates a connectionless \fBRPC\fR service handle, and returns a
 pointer to it. This routine returns \fINULL\fR if it fails, and an error
 message is logged. \fIsendsz\fR and \fIrecvsz\fR are parameters used to specify
@@ -268,7 +278,7 @@
 .na
 \fB\fBsvc_fd_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 This routine creates a service on top of an open and bound file descriptor, and
 returns the handle to it. Typically, this descriptor is a connected file
 descriptor for a connection-oriented transport. \fIsendsz\fR and \fIrecvsz\fR
@@ -282,7 +292,7 @@
 .na
 \fB\fBsvc_raw_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 This routine creates an \fBRPC\fR service handle and returns a pointer to it.
 The transport is really a buffer within the process's address space, so the
 corresponding \fBRPC\fR client should live in the same address space; (see
@@ -300,13 +310,13 @@
 .na
 \fB\fBsvc_tli_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 This routine creates an \fBRPC\fR server handle, and returns a pointer to it.
 \fIfildes\fR is the file descriptor on which the service is listening.  If
 \fIfildes\fR is \fBRPC_ANYFD\fR, it opens a file descriptor on the transport
 specified by \fInetconf\fR. If the file descriptor is unbound and
-\fIbindaddr\fR is non-null \fIfildes\fR is bound to the address specified by
-\fIbindaddr\fR, otherwise \fIfildes\fR is bound to a default address chosen by
+\fIbind_info\fR is non-null \fIfildes\fR is bound to the address specified by
+\fIbind_info\fR, otherwise \fIfildes\fR is bound to a default address chosen by
 the transport. In the case where the default address is chosen, the number of
 outstanding connect requests is set to 8 for connection-oriented transports.
 The user may specify the size of the send and receive buffers with the
@@ -321,7 +331,7 @@
 .na
 \fB\fBsvc_tp_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 \fBsvc_tp_create()\fR creates a server handle for the network specified by
 \fInetconf\fR, and registers itself with the \fBrpcbind\fR service.
 \fIdispatch\fR is called when there is a remote procedure call for the given
@@ -333,9 +343,25 @@
 .sp
 .ne 2
 .na
+\fB\fBsvc_tp_create_addr()\fR\fR
+.ad
+.RS 15n
+\fBsvc_tp_create_addr()\fR creates a server handle for the network specified
+by \fInetconf\fR, and registers itself with the \fBrpcbind\fR service.
+If \fIbind_addr\fR is non-NULL, that address is used for the listener binding.
+If \fIbind_addr\fR is NULL, this call is the same as \fBsvc_tp_create()\fR.
+\fIdispatch\fR is called when there is a remote procedure call for the given
+\fIprognum\fR and \fIversnum\fR; this requires calling \fBsvc_run()\fR.
+\fBsvc_tp_create_addr()\fR returns the service handle if it succeeds,
+otherwise a \fINULL\fR is returned and an error message is logged.
+.RE
+
+.sp
+.ne 2
+.na
 \fB\fBsvc_vc_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 This routine creates a connection-oriented \fBRPC\fR service and returns a
 pointer to it. This routine returns \fINULL\fR if it fails, and an error
 message is logged. The users may specify the size of the send and receive
@@ -349,10 +375,10 @@
 .na
 \fB\fBsvc_door_create()\fR\fR
 .ad
-.RS 21n
+.RS 15n
 This routine creates an RPC server handle over doors for the given program
-\fIprognum\fR and version \fIversnum\fR and returns a pointer to
-it. Doors is a transport mechanism that facilitates fast data transfer between
+\fIprognum\fR and version \fIversnum\fR and returns a pointer to it.
+Doors is a transport mechanism that facilitates fast data transfer between
 processes on the same machine. The user may set the size
 of the send buffer with the parameter \fIsendsz\fR. If \fIsendsz\fR is 0, the
 corresponding default buffer size is 16 Kbyte. If successful, the
--- old/usr/src/man/man4/nfs.4	Mon Jul 17 16:15:19 2017
+++ new/usr/src/man/man4/nfs.4	Mon Jul 17 16:15:19 2017
@@ -19,7 +19,7 @@
 .\" Copyright (c) 2004, Sun Microsystems, Inc. All Rights Reserved.
 .\" Copyright 2016 Nexenta Systems, Inc.
 .\"
-.Dd December 16, 2016
+.Dd December 18, 2016
 .Dt NFS 4
 .Os
 .Sh NAME
@@ -187,6 +187,20 @@
 .Nm mountd .
 The default value is
 .Li 16 .
+.It Sy mountd_port Ns = Ns Ar num
+The IP port number on which
+.Nm mountd
+should listen.
+The default value is
+.Li 0 ,
+which means it should use a default binding.
+.It Sy statd_port Ns = Ns Ar num
+The IP port number on which
+.Nm statd
+should listen.
+The default value is
+.Li 0 ,
+which means it should use a default binding.
 .El
 .Ss Setting nfsmapid_domain
 As described above, the setting for
--- old/usr/src/pkg/manifests/system-library.man3nsl.inc	Mon Jul 17 16:15:20 2017
+++ new/usr/src/pkg/manifests/system-library.man3nsl.inc	Mon Jul 17 16:15:20 2017
@@ -11,7 +11,7 @@
 
 #
 # Copyright 2011, Richard Lowe
-# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
 #
 
 file path=usr/share/man/man3nsl/dial.3nsl
@@ -263,6 +263,8 @@
 link path=usr/share/man/man3nsl/svc_sendreply.3nsl target=rpc_svc_calls.3nsl
 link path=usr/share/man/man3nsl/svc_tli_create.3nsl target=rpc_svc_create.3nsl
 link path=usr/share/man/man3nsl/svc_tp_create.3nsl target=rpc_svc_create.3nsl
+link path=usr/share/man/man3nsl/svc_tp_create_addr.3nsl \
+    target=rpc_svc_create.3nsl
 link path=usr/share/man/man3nsl/svc_unreg.3nsl target=rpc_svc_reg.3nsl
 link path=usr/share/man/man3nsl/svc_unregister.3nsl target=rpc_soc.3nsl
 link path=usr/share/man/man3nsl/svc_vc_create.3nsl target=rpc_svc_create.3nsl
--- old/usr/src/uts/common/rpc/svc.h	Mon Jul 17 16:15:20 2017
+++ new/usr/src/uts/common/rpc/svc.h	Mon Jul 17 16:15:20 2017
@@ -924,6 +924,22 @@
 	 */
 
 /*
+ * Variant of svc_tp_create that accepts a binding address.
+ * If addr == NULL, this is the same as svc_tp_create().
+ */
+extern SVCXPRT	*svc_tp_create_addr(void (*)(struct svc_req *, SVCXPRT *),
+				const rpcprog_t, const rpcvers_t,
+				const struct netconfig *,
+				const struct netbuf *);
+	/*
+	 * void (*dispatch)();			-- dispatch routine
+	 * const rpcprog_t prognum;		-- program number
+	 * const rpcvers_t versnum;		-- version number
+	 * const struct netconfig *nconf;	-- netconfig structure
+	 * const struct netbuf *addr;		-- address to bind
+	 */
+
+/*
  * Generic TLI create routine
  */
 extern  SVCXPRT	*svc_tli_create(const int, const struct netconfig *,
