--- old/usr/src/cmd/cmd-inet/usr.sbin/soconfig.c	Fri Jun  5 08:01:06 2015
+++ new/usr/src/cmd/cmd-inet/usr.sbin/soconfig.c	Fri Jun  5 08:01:06 2015
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <ctype.h>
@@ -54,6 +55,9 @@
  *	soconfig <fam> <type> <protocol>
  *		deregisters
  *
+ *	soconfig -l
+ *		print the in-kernel socket configuration table
+ *
  * Filter Operations (Consolidation Private):
  *
  *	soconfig -F <name> <modname> {auto [top | bottom | before:filter |
@@ -79,6 +83,8 @@
 
 static int	parse_filter_params(int argc, char **argv);
 
+static int	print_socktable();
+
 int
 main(argc, argv)
 	int argc;
@@ -94,6 +100,11 @@
 #endif
 	(void) textdomain(TEXT_DOMAIN);
 
+	if (argc == 1 && strcmp(argv[0], "-l") == 0) {
+		ret = print_socktable();
+		exit(ret);
+	}
+
 	if (argc >= 2 && strcmp(argv[0], "-F") == 0) {
 		argc--; argv++;
 		ret = parse_filter_params(argc, argv);
@@ -128,7 +139,8 @@
 	    "Usage:	soconfig -d <dir>\n"
 	    "\tsoconfig -f <file>\n"
 	    "\tsoconfig <fam> <type> <protocol> <path|module>\n"
-	    "\tsoconfig <fam> <type> <protocol>\n"));
+	    "\tsoconfig <fam> <type> <protocol>\n"
+	    "\tsoconfig -l\n"));
 }
 
 /*
@@ -575,3 +587,59 @@
 	free(socktuples);
 	return (0);
 }
+
+/*
+ *  Print the in-kernel socket configuration table
+ */
+
+static int
+print_socktable()
+{
+	sockconfig_socktable_t sc_table;
+	int i;
+
+	(void) memset(&sc_table, 0, sizeof (sockconfig_socktable_t));
+
+	/* get number of entries */
+	if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE, &sc_table) == -1) {
+		fprintf(stderr,
+		    gettext("cannot get in-kernel socket table: %s\n"),
+		    strerror(errno));
+		return (-1);
+	}
+	if (sc_table.num_of_entries == 0)
+		return (0);
+
+	sc_table.st_entries = calloc(sc_table.num_of_entries,
+	    sizeof (sockconfig_socktable_entry_t));
+	if (sc_table.st_entries == NULL) {
+		fprintf(stderr, gettext("out of memory\n"));
+		return (-1);
+	}
+
+	/* get socket table entries */
+	if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE, &sc_table) == -1) {
+		fprintf(stderr,
+		    gettext("cannot get in-kernel socket table: %s\n"),
+		    strerror(errno));
+		return (-1);
+	}
+
+	printf("%6s %4s %5s %15s %15s %6s %6s\n",
+	    "FAMILY", "TYPE", "PROTO", "STRDEV", "SOCKMOD",
+	    "REFS", "FLAGS");
+	for (i = 0; i < sc_table.num_of_entries; i++) {
+		printf("%6u %4u %5u %15s %15s %6u %#6x\n",
+		    sc_table.st_entries[i].se_family,
+		    sc_table.st_entries[i].se_type,
+		    sc_table.st_entries[i].se_protocol,
+		    (strcmp(sc_table.st_entries[i].se_modname,
+		    "socktpi") == 0) ?
+		    sc_table.st_entries[i].se_strdev : "-",
+		    sc_table.st_entries[i].se_modname,
+		    sc_table.st_entries[i].se_refcnt,
+		    sc_table.st_entries[i].se_flags);
+	}
+	free(sc_table.st_entries);
+	return (0);
+}
--- old/usr/src/man/man1m/soconfig.1m	Fri Jun  5 08:01:06 2015
+++ new/usr/src/man/man1m/soconfig.1m	Fri Jun  5 08:01:06 2015
@@ -1,9 +1,10 @@
 '\" te
 .\"  Copyright (c) 2008, Sun Microsystems, Inc.  All Rights Reserved
+.\"  Copyright 2015 Nexenta Systems, 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 SOCONFIG 1M "Apr 12, 2014"
+.TH SOCONFIG 1M "May 21, 2015"
 .SH NAME
 soconfig \- configure transport providers for use by sockets
 .SH SYNOPSIS
@@ -22,6 +23,11 @@
 \fB/sbin/soconfig\fR \fIfamily\fR \fItype\fR \fIprotocol\fR [\fImodule\fR | \fIpath\fR]
 .fi
 
+.LP
+.nf
+\fB/sbin/soconfig\fR \fB-l\fR
+.fi
+
 .SH DESCRIPTION
 .sp
 .LP
@@ -66,6 +72,15 @@
 An example of \fIfile\fR can be found in the \fBEXAMPLES\fR section below.
 .RE
 
+.sp
+.ne 2
+.na
+\fB\fB-l\fR
+.ad
+.RS 11n
+Print the in-kernel socket configuration table.
+.RE
+
 .SH OPERANDS
 .sp
 .LP
--- old/usr/src/uts/common/fs/sockfs/sockparams.c	Fri Jun  5 08:01:06 2015
+++ new/usr/src/uts/common/fs/sockfs/sockparams.c	Fri Jun  5 08:01:06 2015
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -30,6 +31,7 @@
 #include <sys/sysmacros.h>
 #include <sys/cmn_err.h>
 #include <sys/list.h>
+#include <sys/sunddi.h>
 
 #include <sys/stropts.h>
 #include <sys/socket.h>
@@ -823,4 +825,83 @@
 	if ((error = sockparams_new_filter_impl(ent, &sp_ephem_list)) != 0)
 		sockparams_filter_cleanup_impl(ent, &sphead);
 	return (error);
+}
+
+/*
+ * Setup and return socket configuration table.
+ */
+int
+sockparams_copyout_socktable(uintptr_t socktable)
+{
+	STRUCT_DECL(sockconfig_socktable, st);
+	struct sockparams *sp;
+	uint_t count;
+	uint_t i = 0;
+	int ret = 0;
+	sockconfig_socktable_entry_t *se;
+
+	STRUCT_INIT(st, get_udatamodel());
+	if (ddi_copyin((void *)socktable, STRUCT_BUF(st),
+	    STRUCT_SIZE(st), 0) != 0)
+		return (EFAULT);
+
+	rw_enter(&sockconf_lock, RW_READER);
+
+	count = STRUCT_FGET(st, num_of_entries);
+	/*
+	 * If the output buffer is size zero, just copy out the count.
+	 */
+	if (count == 0) {
+		for (sp = list_head(&sphead); sp != NULL;
+		    sp = list_next(&sphead, sp)) {
+			count++;
+		}
+		STRUCT_FSET(st, num_of_entries, count);
+
+		rw_exit(&sockconf_lock);
+		if (ddi_copyout(STRUCT_BUF(st), (void *)socktable,
+		    STRUCT_SIZE(st), 0) != 0)
+			return (EFAULT);
+
+		return (0);
+	}
+
+	se = kmem_alloc(count * sizeof (sockconfig_socktable_entry_t),
+	    KM_SLEEP);
+	for (sp = list_head(&sphead); sp != NULL;
+	    sp = list_next(&sphead, sp)) {
+		if (i >= count) {
+			/*
+			 * Return if the number of entries has changed.
+			 */
+			rw_exit(&sockconf_lock);
+			kmem_free(se,
+			    count * sizeof (sockconfig_socktable_entry_t));
+			return (EAGAIN);
+		}
+		se[i].se_family = sp->sp_family;
+		se[i].se_type = sp->sp_type;
+		se[i].se_protocol = sp->sp_protocol;
+		(void) strncpy(se[i].se_modname, sp->sp_smod_name,
+		    MODMAXNAMELEN);
+		if (sp->sp_sdev_info.sd_devpath != NULL)
+			(void) strncpy(se[i].se_strdev,
+			    sp->sp_sdev_info.sd_devpath, MAXPATHLEN);
+		se[i].se_refcnt = sp->sp_refcnt;
+		se[i].se_flags = sp->sp_flags;
+		i++;
+	}
+	rw_exit(&sockconf_lock);
+	if (ddi_copyout(se, STRUCT_FGETP(st, st_entries),
+	    i * sizeof (sockconfig_socktable_entry_t), 0) != 0)
+		ret = EFAULT;
+
+	STRUCT_FSET(st, num_of_entries, i);
+	kmem_free(se, count * sizeof (sockconfig_socktable_entry_t));
+
+	if (ddi_copyout(STRUCT_BUF(st), (void *)socktable,
+	    STRUCT_SIZE(st), 0) != 0)
+		ret = EFAULT;
+
+	return (ret);
 }
--- old/usr/src/uts/common/fs/sockfs/socksyscalls.c	Fri Jun  5 08:01:06 2015
+++ new/usr/src/uts/common/fs/sockfs/socksyscalls.c	Fri Jun  5 08:01:06 2015
@@ -24,6 +24,9 @@
  */
 
 /* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
 
 #include <sys/types.h>
 #include <sys/t_lock.h>
@@ -1862,6 +1865,9 @@
 	case SOCKCONFIG_REMOVE_FILTER:
 		error = sockconfig_remove_filter((const char *)arg1);
 		break;
+	case SOCKCONFIG_GET_SOCKTABLE:
+		error = sockparams_copyout_socktable((int)(uintptr_t)arg1);
+		break;
 	default:
 #ifdef	DEBUG
 		cmn_err(CE_NOTE, "sockconfig: unkonwn subcommand %d", cmd);
--- old/usr/src/uts/common/sys/socketvar.h	Fri Jun  5 08:01:07 2015
+++ new/usr/src/uts/common/sys/socketvar.h	Fri Jun  5 08:01:07 2015
@@ -35,6 +35,9 @@
  * software developed by the University of California, Berkeley, and its
  * contributors.
  */
+/*
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ */
 
 #ifndef _SYS_SOCKETVAR_H
 #define	_SYS_SOCKETVAR_H
@@ -506,6 +509,7 @@
 extern int	sockparams_delete(int, int, int);
 extern int	sockparams_new_filter(struct sof_entry *);
 extern void	sockparams_filter_cleanup(struct sof_entry *);
+extern int	sockparams_copyout_socktable(uintptr_t);
 
 extern void smod_init(void);
 extern void smod_add(smod_info_t *);
@@ -975,6 +979,7 @@
 #define	SOCKCONFIG_REMOVE_SOCK		1
 #define	SOCKCONFIG_ADD_FILTER		2
 #define	SOCKCONFIG_REMOVE_FILTER	3
+#define	SOCKCONFIG_GET_SOCKTABLE	4
 
 /*
  * Data structures for configuring socket filters.
@@ -1013,6 +1018,24 @@
 	sof_socktuple_t	*sfp_socktuple;
 };
 
+/*
+ * Data structures for the in-kernel socket configuration table.
+ */
+typedef struct sockconfig_socktable_entry {
+	int		se_family;
+	int		se_type;
+	int		se_protocol;
+	int		se_refcnt;
+	int		se_flags;
+	char		se_modname[MODMAXNAMELEN];
+	char		se_strdev[MAXPATHLEN];
+} sockconfig_socktable_entry_t;
+
+typedef struct sockconfig_socktable {
+	uint_t		num_of_entries;
+	sockconfig_socktable_entry_t *st_entries;
+} sockconfig_socktable_t;
+
 #ifdef	_SYSCALL32
 
 typedef struct sof_socktuple32 {
@@ -1030,6 +1053,11 @@
 	caddr32_t	sfp_socktuple;
 };
 
+typedef struct sockconfig_socktable32 {
+	uint_t		num_of_entries;
+	caddr32_t	st_entries;
+} sockconfig_socktable32_t;
+
 #endif	/* _SYSCALL32 */
 
 #define	SOCKMOD_PATH	"socketmod"	/* dir where sockmods are stored */
