--- old/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile	2015-12-04 14:19:20.806615927 +0300
+++ new/usr/src/cmd/cmd-inet/usr.bin/netstat/Makefile	2015-12-04 14:19:20.816374610 +0300
@@ -28,7 +28,7 @@
 
 PROG=		netstat
 
-LOCALOBJS=	netstat.o unix.o
+LOCALOBJS=	netstat.o
 COMMONOBJS=	compat.o
 
 include ../../../Makefile.cmd
--- old/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c	2015-12-04 14:19:21.008061527 +0300
+++ new/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c	2015-12-04 14:19:21.014536406 +0300
@@ -55,14 +55,19 @@
 #include <kstat.h>
 #include <assert.h>
 #include <locale.h>
+#include <pwd.h>
+#include <limits.h>
 
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/stream.h>
 #include <stropts.h>
 #include <sys/strstat.h>
 #include <sys/tihdr.h>
+#include <procfs.h>
 
 #include <sys/socket.h>
+#include <sys/socketvar.h>
 #include <sys/sockio.h>
 #include <netinet/in.h>
 #include <net/if.h>
@@ -91,7 +96,6 @@
 
 #include "statcommon.h"
 
-extern void	unixpr(kstat_ctl_t *kc);
 
 #define	STR_EXPAND	4
 
@@ -135,6 +139,12 @@
 	struct ifstat	tot;
 };
 
+typedef struct proc_info {
+	char *pr_user;
+	char *pr_fname;
+	char *pr_psargs;
+} proc_info_t;
+
 static	mib_item_t	*mibget(int sd);
 static	void		mibfree(mib_item_t *firstitem);
 static	int		mibopen(void);
@@ -191,6 +201,7 @@
 static void		ire_report(const mib_item_t *item);
 static void		tcp_report(const mib_item_t *item);
 static void		udp_report(const mib_item_t *item);
+static void		uds_report(kstat_ctl_t *);
 static void		group_report(mib_item_t *item);
 static void		dce_report(mib_item_t *item);
 static void		print_ip_stats(mib2_ip_t *ip);
@@ -222,6 +233,8 @@
 static boolean_t	family_selected(int family);
 
 static void		usage(char *);
+static char		*get_username(uid_t);
+proc_info_t		*get_proc_info(pid_t);
 static void 		fatal(int errcode, char *str1, ...);
 
 #define	PLURAL(n) plural((int)n)
@@ -241,6 +254,7 @@
 static	boolean_t	RSECflag = B_FALSE;	/* Security attributes */
 static	boolean_t	Sflag = B_FALSE;	/* Per-protocol Statistics */
 static	boolean_t	Vflag = B_FALSE;	/* Verbose */
+static	boolean_t	Uflag = B_FALSE;	/* Show PID and UID info. */
 static	boolean_t	Pflag = B_FALSE;	/* Net to Media Tables */
 static	boolean_t	Gflag = B_FALSE;	/* Multicast group membership */
 static	boolean_t	MMflag = B_FALSE;	/* Multicast routing table */
@@ -385,7 +399,7 @@
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
-	while ((c = getopt(argc, argv, "adimnrspMgvxf:P:I:DRT:")) != -1) {
+	while ((c = getopt(argc, argv, "adimnrspMgvuxf:P:I:DRT:")) != -1) {
 		switch ((char)c) {
 		case 'a':		/* all connections */
 			Aflag = B_TRUE;
@@ -445,6 +459,10 @@
 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
 			break;
 
+		case 'u':		/* show pid and uid information */
+			Uflag = B_TRUE;
+			break;
+
 		case 'x':		/* turn on debugging */
 			Xflag = B_TRUE;
 			break;
@@ -654,7 +672,7 @@
 		if (family_selected(AF_UNIX) &&
 		    (!(Dflag || Iflag || Rflag || Sflag || Mflag ||
 		    MMflag || Pflag || Gflag)))
-			unixpr(kc);
+			uds_report(kc);
 		(void) kstat_close(kc);
 
 		/* iteration handling code */
@@ -972,7 +990,8 @@
  * for item->mib_id == 0
  */
 static mib_item_t *
-mib_item_diff(mib_item_t *item1, mib_item_t *item2) {
+mib_item_diff(mib_item_t *item1, mib_item_t *item2)
+{
 	int	nitems	= 0; /* no. of items in item2 */
 	mib_item_t *tempp2;  /* walking copy of item2 */
 	mib_item_t *tempp1;  /* walking copy of item1 */
@@ -1498,7 +1517,8 @@
  * mib_item_diff
  */
 static void
-mib_item_destroy(mib_item_t **itemp) {
+mib_item_destroy(mib_item_t **itemp)
+{
 	int	nitems = 0;
 	int	c = 0;
 	mib_item_t *tempp;
@@ -3263,9 +3283,9 @@
 }
 
 static void
-if_report_ip4(mib2_ipAddrEntry_t *ap,
-	char ifname[], char logintname[], struct ifstat *statptr,
-	boolean_t ksp_not_null) {
+if_report_ip4(mib2_ipAddrEntry_t *ap, char ifname[], char logintname[],
+    struct ifstat *statptr, boolean_t ksp_not_null)
+{
 
 	char abuf[MAXHOSTNAMELEN + 1];
 	char dstbuf[MAXHOSTNAMELEN + 1];
@@ -3297,7 +3317,7 @@
 		(void) printf("%-5s %-4u ", logintname, ap->ipAdEntInfo.ae_mtu);
 		if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
 			(void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr, abuf,
-			sizeof (abuf));
+			    sizeof (abuf));
 		else
 			(void) pr_netaddr(ap->ipAdEntAddr, ap->ipAdEntNetMask,
 			    abuf, sizeof (abuf));
@@ -3311,9 +3331,9 @@
 }
 
 static void
-if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
-	char ifname[], char logintname[], struct ifstat *statptr,
-	boolean_t ksp_not_null) {
+if_report_ip6(mib2_ipv6AddrEntry_t *ap6, char ifname[], char logintname[],
+    struct ifstat *statptr, boolean_t ksp_not_null)
+{
 
 	char abuf[MAXHOSTNAMELEN + 1];
 	char dstbuf[MAXHOSTNAMELEN + 1];
@@ -4742,6 +4762,16 @@
 "   State\n"
 "-------------------- -------------------- ----- ------ ----- ------ "
 "-----------\n";
+static const char tcp_hdr_v4_pid[] =
+"   Local Address        Remote Address      User     Pid     Command     Swind"
+"   Send-Q  Rwind  Recv-Q    State\n"
+"-------------------- -------------------- -------- ------ ------------- ------"
+"- ------ ------- ------ -----------\n";
+static const char tcp_hdr_v4_pid_verbose[] =
+"Local/Remote Address  Swind   Snext     Suna    Rwind   Rnext     Rack    Rto "
+"  Mss     State      User    Pid      Command\n"
+"-------------------- ------- -------- -------- ------- -------- -------- -----"
+" ----- ----------- -------- ------ --------------\n";
 
 static const char tcp_hdr_v6[] =
 "\nTCP: IPv6\n";
@@ -4755,23 +4785,37 @@
 "Swind Send-Q Rwind Recv-Q   State      If\n"
 "--------------------------------- --------------------------------- "
 "----- ------ ----- ------ ----------- -----\n";
+static const char tcp_hdr_v6_pid[] =
+"   Local Address                     Remote Address                   User"
+"    Pid      Command      Swind  Send-Q  Rwind  Recv-Q   State      If\n"
+"--------------------------------- --------------------------------- --------"
+" ------ -------------- ------- ------ ------- ------ ----------- -----\n";
+static const char tcp_hdr_v6_pid_verbose[] =
+"Local/Remote Address               Swind   Snext     Suna    Rwind   Rnext"
+"     Rack    Rto   Mss    State      If     User    Pid     Command\n"
+"--------------------------------- ------- -------- -------- ------- --------"
+" -------- ----- ----- ----------- ----- -------- ------ --------------\n";
 
 static boolean_t tcp_report_item_v4(const mib2_tcpConnEntry_t *,
-    boolean_t first, const mib2_transportMLPEntry_t *);
+    conn_pid_info_t *, boolean_t first,
+    const mib2_transportMLPEntry_t *);
 static boolean_t tcp_report_item_v6(const mib2_tcp6ConnEntry_t *,
-    boolean_t first, const mib2_transportMLPEntry_t *);
+    conn_pid_info_t *, boolean_t first,
+    const mib2_transportMLPEntry_t *);
+
 
 static void
 tcp_report(const mib_item_t *item)
 {
-	int			jtemp = 0;
-	boolean_t		print_hdr_once_v4 = B_TRUE;
-	boolean_t		print_hdr_once_v6 = B_TRUE;
-	mib2_tcpConnEntry_t	*tp;
-	mib2_tcp6ConnEntry_t	*tp6;
-	mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
-	mib2_transportMLPEntry_t **v4a, **v6a;
-	mib2_transportMLPEntry_t *aptr;
+	int				jtemp = 0;
+	boolean_t			print_hdr_once_v4 = B_TRUE;
+	boolean_t			print_hdr_once_v6 = B_TRUE;
+	mib2_tcpConnEntry_t		*tp;
+	mib2_tcp6ConnEntry_t		*tp6;
+	mib2_transportMLPEntry_t 	**v4_attrs, **v6_attrs;
+	mib2_transportMLPEntry_t 	**v4a, **v6a;
+	mib2_transportMLPEntry_t 	*aptr;
+	conn_pid_info_t			*cpi;
 
 	if (!protocol_selected(IPPROTO_TCP))
 		return;
@@ -4804,7 +4848,11 @@
 		if (!((item->group == MIB2_TCP &&
 		    item->mib_id == MIB2_TCP_CONN) ||
 		    (item->group == MIB2_TCP6 &&
-		    item->mib_id == MIB2_TCP6_CONN)))
+		    item->mib_id == MIB2_TCP6_CONN) ||
+		    (item->group == MIB2_TCP &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO) ||
+		    (item->group == MIB2_TCP6 &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO)))
 			continue; /* 'for' loop 1 */
 
 		if (item->group == MIB2_TCP && !family_selected(AF_INET))
@@ -4812,7 +4860,8 @@
 		else if (item->group == MIB2_TCP6 && !family_selected(AF_INET6))
 			continue; /* 'for' loop 1 */
 
-		if (item->group == MIB2_TCP) {
+		if ((!Uflag) && item->group == MIB2_TCP &&
+		    item->mib_id == MIB2_TCP_CONN) {
 			for (tp = (mib2_tcpConnEntry_t *)item->valp;
 			    (char *)tp < (char *)item->valp + item->length;
 			    /* LINTED: (note 1) */
@@ -4820,9 +4869,10 @@
 			    tcpConnEntrySize)) {
 				aptr = v4a == NULL ? NULL : *v4a++;
 				print_hdr_once_v4 = tcp_report_item_v4(tp,
-				    print_hdr_once_v4, aptr);
+				    NULL, print_hdr_once_v4, aptr);
 			}
-		} else {
+		} else if ((!Uflag) && item->group == MIB2_TCP6 &&
+		    item->mib_id == MIB2_TCP6_CONN) {
 			for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
 			    (char *)tp6 < (char *)item->valp + item->length;
 			    /* LINTED: (note 1) */
@@ -4830,9 +4880,38 @@
 			    tcp6ConnEntrySize)) {
 				aptr = v6a == NULL ? NULL : *v6a++;
 				print_hdr_once_v6 = tcp_report_item_v6(tp6,
-				    print_hdr_once_v6, aptr);
+				    NULL, print_hdr_once_v6, aptr);
+			}
+		} else if ((Uflag) && item->group == MIB2_TCP &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO) {
+			for (tp = (mib2_tcpConnEntry_t *)item->valp;
+			    (char *)tp < (char *)item->valp + item->length;
+			    /* LINTED: (note 1) */
+			    tp = (mib2_tcpConnEntry_t *)((char *)cpi +
+			    cpi->cpi_tot_size)) {
+				aptr = v4a == NULL ? NULL : *v4a++;
+				/* LINTED: (note 1) */
+				cpi = (conn_pid_info_t *)((char *)tp +
+				    tcpConnEntrySize);
+				print_hdr_once_v4 = tcp_report_item_v4(tp,
+				    cpi, print_hdr_once_v4, aptr);
+			}
+		} else if ((Uflag) && item->group == MIB2_TCP6 &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO) {
+			for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
+			    (char *)tp6 < (char *)item->valp + item->length;
+			    /* LINTED: (note 1) */
+			    tp6 = (mib2_tcp6ConnEntry_t *)((char *)cpi +
+			    cpi->cpi_tot_size)) {
+				aptr = v6a == NULL ? NULL : *v6a++;
+				/* LINTED: (note 1) */
+				cpi = (conn_pid_info_t *)((char *)tp6 +
+				    tcp6ConnEntrySize);
+				print_hdr_once_v6 = tcp_report_item_v6(tp6,
+				    cpi, print_hdr_once_v6, aptr);
 			}
 		}
+
 	} /* 'for' loop 1 ends */
 	(void) fflush(stdout);
 
@@ -4843,8 +4922,8 @@
 }
 
 static boolean_t
-tcp_report_item_v4(const mib2_tcpConnEntry_t *tp, boolean_t first,
-    const mib2_transportMLPEntry_t *attr)
+tcp_report_item_v4(const mib2_tcpConnEntry_t *tp, conn_pid_info_t *cpi,
+    boolean_t first, const mib2_transportMLPEntry_t *attr)
 {
 	/*
 	 * lname and fname below are for the hostname as well as the portname
@@ -4854,15 +4933,21 @@
 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
 	char	fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
 
+
 	if (!(Aflag || tp->tcpConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
 		return (first); /* Nothing to print */
 
 	if (first) {
 		(void) printf(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4);
-		(void) printf(Vflag ? tcp_hdr_v4_verbose : tcp_hdr_v4_normal);
+		if (Uflag)
+			(void) printf(Vflag ? tcp_hdr_v4_pid_verbose :
+			    tcp_hdr_v4_pid);
+		else
+			(void) printf(Vflag ? tcp_hdr_v4_verbose :
+			    tcp_hdr_v4_normal);
 	}
 
-	if (Vflag) {
+	if ((!Uflag) && Vflag) {
 		(void) printf("%-20s\n%-20s %5u %08x %08x %5u %08x %08x "
 		    "%5u %5u %s\n",
 		    pr_ap(tp->tcpConnLocalAddress,
@@ -4878,7 +4963,7 @@
 		    tp->tcpConnEntryInfo.ce_rto,
 		    tp->tcpConnEntryInfo.ce_mss,
 		    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
-	} else {
+	} else if ((!Uflag) && (!Vflag)) {
 		int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
 		    (int)tp->tcpConnEntryInfo.ce_suna - 1;
 		int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
@@ -4894,6 +4979,54 @@
 		    tp->tcpConnEntryInfo.ce_rwnd,
 		    (rq >= 0) ? rq : 0,
 		    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
+	} else if (Uflag && Vflag) {
+		int i = 0;
+		pid_t *pids = cpi->cpi_pids;
+		proc_info_t *pinfo;
+		do {
+			pinfo = get_proc_info(*pids);
+			(void) printf("%-20s\n%-20s %7u %08x %08x %7u %08x "
+			    "%08x %5u %5u %-11s %-8.8s %6u %s\n",
+			    pr_ap(tp->tcpConnLocalAddress,
+			    tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
+			    pr_ap(tp->tcpConnRemAddress,
+			    tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
+			    tp->tcpConnEntryInfo.ce_swnd,
+			    tp->tcpConnEntryInfo.ce_snxt,
+			    tp->tcpConnEntryInfo.ce_suna,
+			    tp->tcpConnEntryInfo.ce_rwnd,
+			    tp->tcpConnEntryInfo.ce_rnxt,
+			    tp->tcpConnEntryInfo.ce_rack,
+			    tp->tcpConnEntryInfo.ce_rto,
+			    tp->tcpConnEntryInfo.ce_mss,
+			    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr),
+			    pinfo->pr_user, (int)*pids, pinfo->pr_psargs);
+			i++; pids++;
+		} while (i < cpi->cpi_pids_cnt);
+	} else if (Uflag && (!Vflag)) {
+		int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
+		    (int)tp->tcpConnEntryInfo.ce_suna - 1;
+		int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
+		    (int)tp->tcpConnEntryInfo.ce_rack;
+		int i = 0;
+		pid_t *pids = cpi->cpi_pids;
+		proc_info_t *pinfo;
+		do {
+			pinfo = get_proc_info(*pids);
+			(void) printf("%-20s %-20s %-8.8s %6u %-13.13s %7u "
+			    "%6d %7u %6d %s\n",
+			    pr_ap(tp->tcpConnLocalAddress,
+			    tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
+			    pr_ap(tp->tcpConnRemAddress,
+			    tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
+			    pinfo->pr_user, (int)*pids, pinfo->pr_fname,
+			    tp->tcpConnEntryInfo.ce_swnd,
+			    (sq >= 0) ? sq : 0,
+			    tp->tcpConnEntryInfo.ce_rwnd,
+			    (rq >= 0) ? rq : 0,
+			    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
+			i++; pids++;
+		} while (i < cpi->cpi_pids_cnt);
 	}
 
 	print_transport_label(attr);
@@ -4902,8 +5035,8 @@
 }
 
 static boolean_t
-tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6, boolean_t first,
-    const mib2_transportMLPEntry_t *attr)
+tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6, conn_pid_info_t *cpi,
+    boolean_t first, const mib2_transportMLPEntry_t *attr)
 {
 	/*
 	 * lname and fname below are for the hostname as well as the portname
@@ -4920,7 +5053,12 @@
 
 	if (first) {
 		(void) printf(tcp_hdr_v6);
-		(void) printf(Vflag ? tcp_hdr_v6_verbose : tcp_hdr_v6_normal);
+		if (Uflag)
+			(void) printf(Vflag ? tcp_hdr_v6_pid_verbose :
+			    tcp_hdr_v6_pid);
+		else
+			(void) printf(Vflag ? tcp_hdr_v6_verbose :
+			    tcp_hdr_v6_normal);
 	}
 
 	ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
@@ -4928,7 +5066,7 @@
 	if (ifnamep == NULL)
 		ifnamep = "";
 
-	if (Vflag) {
+	if ((!Uflag) && Vflag) {
 		(void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
 		    "%5u %5u %-11s %s\n",
 		    pr_ap6(&tp6->tcp6ConnLocalAddress,
@@ -4945,7 +5083,7 @@
 		    tp6->tcp6ConnEntryInfo.ce_mss,
 		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
 		    ifnamep);
-	} else {
+	} else if ((!Uflag) && (!Vflag)) {
 		int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
 		    (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
 		int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
@@ -4962,6 +5100,59 @@
 		    (rq >= 0) ? rq : 0,
 		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
 		    ifnamep);
+	} else if (Uflag && Vflag) {
+		int i = 0;
+		pid_t *pids = cpi->cpi_pids;
+		proc_info_t *pinfo;
+		do {
+			pinfo = get_proc_info(*pids);
+			(void) printf("%-33s\n%-33s %7u %08x %08x %7u %08x "
+			    "%08x %5u %5u %-11s %-5.5s %-8.8s %6u %s\n",
+			    pr_ap6(&tp6->tcp6ConnLocalAddress,
+			    tp6->tcp6ConnLocalPort, "tcp", lname,
+			    sizeof (lname)),
+			    pr_ap6(&tp6->tcp6ConnRemAddress,
+			    tp6->tcp6ConnRemPort, "tcp", fname,
+			    sizeof (fname)),
+			    tp6->tcp6ConnEntryInfo.ce_swnd,
+			    tp6->tcp6ConnEntryInfo.ce_snxt,
+			    tp6->tcp6ConnEntryInfo.ce_suna,
+			    tp6->tcp6ConnEntryInfo.ce_rwnd,
+			    tp6->tcp6ConnEntryInfo.ce_rnxt,
+			    tp6->tcp6ConnEntryInfo.ce_rack,
+			    tp6->tcp6ConnEntryInfo.ce_rto,
+			    tp6->tcp6ConnEntryInfo.ce_mss,
+			    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
+			    ifnamep, pinfo->pr_user, (int)*pids,
+			    pinfo->pr_psargs);
+			i++; pids++;
+		} while (i < cpi->cpi_pids_cnt);
+	} else if (Uflag && (!Vflag)) {
+		int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
+		    (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
+		int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
+		    (int)tp6->tcp6ConnEntryInfo.ce_rack;
+		int i = 0;
+		pid_t *pids = cpi->cpi_pids;
+		proc_info_t *pinfo;
+		do {
+			pinfo = get_proc_info(*pids);
+			(void) printf("%-33s %-33s %-8.8s %6u %-14.14s %7d "
+			    "%6u %7d %6d %-11s %s\n",
+			    pr_ap6(&tp6->tcp6ConnLocalAddress,
+			    tp6->tcp6ConnLocalPort, "tcp", lname,
+			    sizeof (lname)),
+			    pr_ap6(&tp6->tcp6ConnRemAddress,
+			    tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
+			    pinfo->pr_user, (int)*pids, pinfo->pr_fname,
+			    tp6->tcp6ConnEntryInfo.ce_swnd,
+			    (sq >= 0) ? sq : 0,
+			    tp6->tcp6ConnEntryInfo.ce_rwnd,
+			    (rq >= 0) ? rq : 0,
+			    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
+			    ifnamep);
+			i++; pids++;
+		} while (i < cpi->cpi_pids_cnt);
 	}
 
 	print_transport_label(attr);
@@ -4972,31 +5163,55 @@
 /* ------------------------------- UDP_REPORT------------------------------- */
 
 static boolean_t udp_report_item_v4(const mib2_udpEntry_t *ude,
-    boolean_t first, const mib2_transportMLPEntry_t *attr);
+    conn_pid_info_t *cpi, boolean_t first,
+    const mib2_transportMLPEntry_t *attr);
 static boolean_t udp_report_item_v6(const mib2_udp6Entry_t *ude6,
-    boolean_t first, const mib2_transportMLPEntry_t *attr);
+    conn_pid_info_t *cpi, boolean_t first,
+    const mib2_transportMLPEntry_t *attr);
 
 static const char udp_hdr_v4[] =
 "   Local Address        Remote Address      State\n"
 "-------------------- -------------------- ----------\n";
+static const char udp_hdr_v4_pid[] =
+"   Local Address        Remote Address      User    Pid   "
+"   Command       State\n"
+"-------------------- -------------------- -------- ------ "
+"-------------- ----------\n";
+static const char udp_hdr_v4_pid_verbose[] =
+"   Local Address        Remote Address      User    Pid     State    "
+"   Command\n"
+"-------------------- -------------------- -------- ------ ---------- "
+"----------------\n";
 
 static const char udp_hdr_v6[] =
 "   Local Address                     Remote Address                 "
 "  State      If\n"
 "--------------------------------- --------------------------------- "
 "---------- -----\n";
+static const char udp_hdr_v6_pid[] =
+"   Local Address                     Remote Address                 "
+"  User    Pid      Command       State      If\n"
+"--------------------------------- --------------------------------- "
+"-------- ------ -------------- ---------- -----\n";
+static const char udp_hdr_v6_pid_verbose[] =
+"   Local Address                     Remote Address                 "
+"  User    Pid     State      If     Command\n"
+"--------------------------------- --------------------------------- "
+"-------- ------ ---------- ----- ----------------\n";
+
 
 static void
 udp_report(const mib_item_t *item)
 {
-	int			jtemp = 0;
-	boolean_t		print_hdr_once_v4 = B_TRUE;
-	boolean_t		print_hdr_once_v6 = B_TRUE;
-	mib2_udpEntry_t		*ude;
-	mib2_udp6Entry_t	*ude6;
-	mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
-	mib2_transportMLPEntry_t **v4a, **v6a;
-	mib2_transportMLPEntry_t *aptr;
+	int				jtemp = 0;
+	boolean_t			print_hdr_once_v4 = B_TRUE;
+	boolean_t			print_hdr_once_v6 = B_TRUE;
+	mib2_udpEntry_t			*ude;
+	mib2_udp6Entry_t		*ude6;
+	mib2_transportMLPEntry_t	**v4_attrs, **v6_attrs;
+	mib2_transportMLPEntry_t	**v4a, **v6a;
+	mib2_transportMLPEntry_t	*aptr;
+	conn_pid_info_t			*cpi;
 
 	if (!protocol_selected(IPPROTO_UDP))
 		return;
@@ -5027,7 +5242,11 @@
 		if (!((item->group == MIB2_UDP &&
 		    item->mib_id == MIB2_UDP_ENTRY) ||
 		    (item->group == MIB2_UDP6 &&
-		    item->mib_id == MIB2_UDP6_ENTRY)))
+		    item->mib_id == MIB2_UDP6_ENTRY) ||
+		    (item->group == MIB2_UDP &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO) ||
+		    (item->group == MIB2_UDP6 &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO)))
 			continue; /* 'for' loop 1 */
 
 		if (item->group == MIB2_UDP && !family_selected(AF_INET))
@@ -5036,7 +5255,8 @@
 			continue; /* 'for' loop 1 */
 
 		/*	xxx.xxx.xxx.xxx,pppp  sss... */
-		if (item->group == MIB2_UDP) {
+		if ((!Uflag) && item->group == MIB2_UDP &&
+		    item->mib_id == MIB2_UDP_ENTRY) {
 			for (ude = (mib2_udpEntry_t *)item->valp;
 			    (char *)ude < (char *)item->valp + item->length;
 			    /* LINTED: (note 1) */
@@ -5044,9 +5264,10 @@
 			    udpEntrySize)) {
 				aptr = v4a == NULL ? NULL : *v4a++;
 				print_hdr_once_v4 = udp_report_item_v4(ude,
-				    print_hdr_once_v4, aptr);
+				    NULL, print_hdr_once_v4, aptr);
 			}
-		} else {
+		} else if ((!Uflag) && item->group == MIB2_UDP6 &&
+		    item->mib_id == MIB2_UDP6_ENTRY) {
 			for (ude6 = (mib2_udp6Entry_t *)item->valp;
 			    (char *)ude6 < (char *)item->valp + item->length;
 			    /* LINTED: (note 1) */
@@ -5054,7 +5275,35 @@
 			    udp6EntrySize)) {
 				aptr = v6a == NULL ? NULL : *v6a++;
 				print_hdr_once_v6 = udp_report_item_v6(ude6,
-				    print_hdr_once_v6, aptr);
+				    NULL, print_hdr_once_v6, aptr);
+			}
+		} else if ((Uflag) && item->group == MIB2_UDP &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO) {
+			for (ude = (mib2_udpEntry_t *)item->valp;
+			    (char *)ude < (char *)item->valp + item->length;
+			    /* LINTED: (note 1) */
+			    ude = (mib2_udpEntry_t *)((char *)cpi +
+			    cpi->cpi_tot_size)) {
+				aptr = v4a == NULL ? NULL : *v4a++;
+				/* LINTED: (note 1) */
+				cpi = (conn_pid_info_t *)((char *)ude +
+				    udpEntrySize);
+				print_hdr_once_v4 = udp_report_item_v4(ude,
+				    cpi, print_hdr_once_v4, aptr);
+			}
+		} else if ((Uflag) && item->group == MIB2_UDP6 &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO) {
+			for (ude6 = (mib2_udp6Entry_t *)item->valp;
+			    (char *)ude6 < (char *)item->valp + item->length;
+			    /* LINTED: (note 1) */
+			    ude6 = (mib2_udp6Entry_t *)((char *)cpi +
+			    cpi->cpi_tot_size)) {
+				aptr = v6a == NULL ? NULL : *v6a++;
+				/* LINTED: (note 1) */
+				cpi = (conn_pid_info_t *)((char *)ude6 +
+				    udp6EntrySize);
+				print_hdr_once_v6 = udp_report_item_v6(ude6,
+				    cpi, print_hdr_once_v6, aptr);
 			}
 		}
 	} /* 'for' loop 1 ends */
@@ -5067,8 +5316,8 @@
 }
 
 static boolean_t
-udp_report_item_v4(const mib2_udpEntry_t *ude, boolean_t first,
-    const mib2_transportMLPEntry_t *attr)
+udp_report_item_v4(const mib2_udpEntry_t *ude, conn_pid_info_t *cpi,
+    boolean_t first, const mib2_transportMLPEntry_t *attr)
 {
 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
 			/* hostname + portname */
@@ -5078,19 +5327,47 @@
 
 	if (first) {
 		(void) printf(v4compat ? "\nUDP\n" : "\nUDP: IPv4\n");
-		(void) printf(udp_hdr_v4);
+
+		if (Uflag)
+			(void) printf(Vflag ? udp_hdr_v4_pid_verbose :
+			    udp_hdr_v4_pid);
+		else
+			(void) printf(udp_hdr_v4);
+
 		first = B_FALSE;
 	}
 
-	(void) printf("%-20s ",
+	(void) printf("%-20s %-20s ",
 	    pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
-	    lname, sizeof (lname)));
-	(void) printf("%-20s %s\n",
+	    lname, sizeof (lname)),
 	    ude->udpEntryInfo.ue_state == MIB2_UDP_connected ?
 	    pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
 	    ude->udpEntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
-	    "",
-	    miudp_state(ude->udpEntryInfo.ue_state, attr));
+	    "");
+	if (!Uflag) {
+		(void) printf("%s\n",
+		    miudp_state(ude->udpEntryInfo.ue_state, attr));
+	} else {
+		int i = 0;
+		pid_t *pids = cpi->cpi_pids;
+		proc_info_t *pinfo;
+		do {
+			pinfo = get_proc_info(*pids);
+			(void) printf("%-8.8s %6u ", pinfo->pr_user,
+			    (int)*pids);
+			if (Vflag) {
+				(void) printf("%-10.10s %s\n",
+				    miudp_state(ude->udpEntryInfo.ue_state,
+				    attr),
+				    pinfo->pr_psargs);
+			} else {
+				(void) printf("%-14.14s %s\n", pinfo->pr_fname,
+				    miudp_state(ude->udpEntryInfo.ue_state,
+				    attr));
+			}
+			i++; pids++;
+		} while (i < cpi->cpi_pids_cnt);
+	}
 
 	print_transport_label(attr);
 
@@ -5098,8 +5375,8 @@
 }
 
 static boolean_t
-udp_report_item_v6(const mib2_udp6Entry_t *ude6, boolean_t first,
-    const mib2_transportMLPEntry_t *attr)
+udp_report_item_v6(const mib2_udp6Entry_t *ude6, conn_pid_info_t *cpi,
+    boolean_t first, const mib2_transportMLPEntry_t *attr)
 {
 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
 			/* hostname + portname */
@@ -5111,23 +5388,54 @@
 
 	if (first) {
 		(void) printf("\nUDP: IPv6\n");
-		(void) printf(udp_hdr_v6);
+
+		if (Uflag)
+			(void) printf(Vflag ? udp_hdr_v6_pid_verbose :
+			    udp_hdr_v6_pid);
+		else
+			(void) printf(udp_hdr_v6);
+
 		first = B_FALSE;
 	}
 
 	ifnamep = (ude6->udp6IfIndex != 0) ?
 	    if_indextoname(ude6->udp6IfIndex, ifname) : NULL;
 
-	(void) printf("%-33s ",
+	(void) printf("%-33s %-33s ",
 	    pr_ap6(&ude6->udp6LocalAddress,
-	    ude6->udp6LocalPort, "udp", lname, sizeof (lname)));
-	(void) printf("%-33s %-10s %s\n",
+	    ude6->udp6LocalPort, "udp", lname, sizeof (lname)),
 	    ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected ?
 	    pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
 	    ude6->udp6EntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
-	    "",
-	    miudp_state(ude6->udp6EntryInfo.ue_state, attr),
-	    ifnamep == NULL ? "" : ifnamep);
+	    "");
+	if (!Uflag) {
+		(void) printf("%-10s %s\n",
+		    miudp_state(ude6->udp6EntryInfo.ue_state, attr),
+		    ifnamep == NULL ? "" : ifnamep);
+	} else {
+		int i = 0;
+		pid_t *pids = cpi->cpi_pids;
+		proc_info_t *pinfo;
+		do {
+			pinfo = get_proc_info(*pids);
+			(void) printf("%-8.8s %6u ", pinfo->pr_user,
+			    (int)*pids);
+			if (Vflag) {
+				(void) printf("%-10.10s %-5.5s %s\n",
+				    miudp_state(ude6->udp6EntryInfo.ue_state,
+				    attr),
+				    ifnamep == NULL ? "" : ifnamep,
+				    pinfo->pr_psargs);
+			} else {
+				(void) printf("%-14.14s %-10.10s %s\n",
+				    pinfo->pr_fname,
+				    miudp_state(ude6->udp6EntryInfo.ue_state,
+				    attr),
+				    ifnamep == NULL ? "" : ifnamep);
+			}
+			i++; pids++;
+		} while (i < cpi->cpi_pids_cnt);
+	}
 
 	print_transport_label(attr);
 
@@ -5143,6 +5451,16 @@
 "Swind  Send-Q Rwind  Recv-Q StrsI/O  State\n"
 "------------------------------- ------------------------------- "
 "------ ------ ------ ------ ------- -----------";
+static const char sctp_hdr_pid[] =
+"        Local Address                   Remote Address          "
+"Swind  Send-Q Rwind  Recv-Q StrsI/O   User    Pid      Command      State\n"
+"------------------------------- ------------------------------- ------ "
+"------ ------ ------ ------- -------- ------ -------------- -----------";
+static const char sctp_hdr_pid_verbose[] =
+"        Local Address                   Remote Address          "
+"Swind  Send-Q Rwind  Recv-Q StrsI/O   User    Pid    State         Command\n"
+"------------------------------- ------------------------------- ------ "
+"------ ------ ------ ------- -------- ------ ----------- --------------";
 
 static const char *
 nssctp_state(int state, const mib2_transportMLPEntry_t *attr)
@@ -5309,8 +5627,9 @@
 	}
 }
 
-static void
-sctp_conn_report_item(const mib_item_t *head, const mib2_sctpConnEntry_t *sp,
+static boolean_t
+sctp_conn_report_item(const mib_item_t *head, conn_pid_info_t *cpi,
+    boolean_t print_sctp_hdr, const mib2_sctpConnEntry_t *sp,
     const mib2_transportMLPEntry_t *attr)
 {
 	char		lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
@@ -5322,24 +5641,65 @@
 	uint32_t	id = sp->sctpAssocId;
 	boolean_t	printfirst = B_TRUE;
 
+	if (print_sctp_hdr == B_TRUE) {
+		(void) puts(sctp_hdr);
+		if (Uflag)
+			(void) puts(Vflag? sctp_hdr_pid_verbose: sctp_hdr_pid);
+		else
+			(void) puts(sctp_hdr_normal);
+
+		print_sctp_hdr = B_FALSE;
+	}
+
 	sctp_pr_addr(sp->sctpAssocRemPrimAddrType, fname, sizeof (fname),
 	    &sp->sctpAssocRemPrimAddr, sp->sctpAssocRemPort);
 	sctp_pr_addr(sp->sctpAssocRemPrimAddrType, lname, sizeof (lname),
 	    &sp->sctpAssocLocPrimAddr, sp->sctpAssocLocalPort);
 
-	(void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
-	    lname, fname,
-	    sp->sctpConnEntryInfo.ce_swnd,
-	    sp->sctpConnEntryInfo.ce_sendq,
-	    sp->sctpConnEntryInfo.ce_rwnd,
-	    sp->sctpConnEntryInfo.ce_recvq,
-	    sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
-	    nssctp_state(sp->sctpAssocState, attr));
+	if (Uflag) {
+		int i = 0;
+		pid_t *pids = cpi->cpi_pids;
+		proc_info_t *pinfo;
+		do {
+			pinfo = get_proc_info(*pids);
+			(void) printf("%-31s %-31s %6u %6d %6u %6d "
+			    "%3d/%-3d %-8.8s %6u ",
+			    lname, fname,
+			    sp->sctpConnEntryInfo.ce_swnd,
+			    sp->sctpConnEntryInfo.ce_sendq,
+			    sp->sctpConnEntryInfo.ce_rwnd,
+			    sp->sctpConnEntryInfo.ce_recvq,
+			    sp->sctpAssocInStreams,
+			    sp->sctpAssocOutStreams,
+			    pinfo->pr_user, (int)*pids);
+			if (Vflag) {
+				(void) printf("%-11.11s %s\n",
+				    nssctp_state(sp->sctpAssocState, attr),
+				    pinfo->pr_psargs);
+			} else {
+				(void) printf("%-14.14s %s\n",
+				    pinfo->pr_fname,
+				    nssctp_state(sp->sctpAssocState, attr));
+			}
+			i++; pids++;
+		} while (i < cpi->cpi_pids_cnt);
+
+	} else {
+
+		(void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
+		    lname, fname,
+		    sp->sctpConnEntryInfo.ce_swnd,
+		    sp->sctpConnEntryInfo.ce_sendq,
+		    sp->sctpConnEntryInfo.ce_rwnd,
+		    sp->sctpConnEntryInfo.ce_recvq,
+		    sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
+		    nssctp_state(sp->sctpAssocState, attr));
+	}
 
 	print_transport_label(attr);
 
 	if (!Vflag) {
-		return;
+		return (print_sctp_hdr);
 	}
 
 	/* Print remote addresses/local addresses on following lines */
@@ -5382,6 +5742,8 @@
 	if (printfirst == B_FALSE) {
 		(void) puts(">");
 	}
+
+	return (print_sctp_hdr);
 }
 
 static void
@@ -5389,9 +5751,10 @@
 {
 	const mib_item_t		*head;
 	const mib2_sctpConnEntry_t	*sp;
-	boolean_t		first = B_TRUE;
-	mib2_transportMLPEntry_t **attrs, **aptr;
-	mib2_transportMLPEntry_t *attr;
+	boolean_t 			print_sctp_hdr_once = B_TRUE;
+	mib2_transportMLPEntry_t 	**attrs, **aptr;
+	mib2_transportMLPEntry_t	*attr;
+	conn_pid_info_t			*cpi;
 
 	/*
 	 * Preparation pass: the kernel returns separate entries for SCTP
@@ -5407,23 +5770,44 @@
 	head = item;
 	for (; item != NULL; item = item->next_item) {
 
-		if (!(item->group == MIB2_SCTP &&
-		    item->mib_id == MIB2_SCTP_CONN))
+		if (!((item->group == MIB2_SCTP &&
+		    item->mib_id == MIB2_SCTP_CONN) ||
+		    (item->group == MIB2_SCTP &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO)))
 			continue;
 
-		for (sp = item->valp;
-		    (char *)sp < (char *)item->valp + item->length;
-		    /* LINTED: (note 1) */
-		    sp = (mib2_sctpConnEntry_t *)((char *)sp + sctpEntrySize)) {
-			attr = aptr == NULL ? NULL : *aptr++;
-			if (Aflag ||
-			    sp->sctpAssocState >= MIB2_SCTP_established) {
-				if (first == B_TRUE) {
-					(void) puts(sctp_hdr);
-					(void) puts(sctp_hdr_normal);
-					first = B_FALSE;
-				}
-				sctp_conn_report_item(head, sp, attr);
+		if ((!Uflag) && item->group == MIB2_SCTP &&
+		    item->mib_id == MIB2_SCTP_CONN) {
+			for (sp = item->valp;
+			    (char *)sp < (char *)item->valp + item->length;
+			    /* LINTED: (note 1) */
+			    sp = (mib2_sctpConnEntry_t *)((char *)sp +
+			    sctpEntrySize)) {
+				if (!(Aflag ||
+				    sp->sctpAssocState >=
+				    MIB2_SCTP_established))
+					continue;
+				attr = aptr == NULL ? NULL : *aptr++;
+				print_sctp_hdr_once = sctp_conn_report_item(
+				    head, NULL, print_sctp_hdr_once, sp, attr);
+			}
+		} else if ((Uflag) && item->group == MIB2_SCTP &&
+		    item->mib_id == EXPER_XPORT_PROC_INFO) {
+			for (sp = (mib2_sctpConnEntry_t *)item->valp;
+			    (char *)sp < (char *)item->valp + item->length;
+			    /* LINTED: (note 1) */
+			    sp = (mib2_sctpConnEntry_t *)((char *)cpi +
+			    cpi->cpi_tot_size)) {
+				/* LINTED: (note 1) */
+				cpi = (conn_pid_info_t *)((char *)sp +
+				    sctpEntrySize);
+				if (!(Aflag ||
+				    sp->sctpAssocState >=
+				    MIB2_SCTP_established))
+					continue;
+				attr = aptr == NULL ? NULL : *aptr++;
+				print_sctp_hdr_once = sctp_conn_report_item(
+				    head, cpi, print_sctp_hdr_once, sp, attr);
 			}
 		}
 	}
@@ -5450,8 +5834,7 @@
 }
 
 static char *
-pktscale(n)
-	int n;
+pktscale(int n)
 {
 	static char buf[6];
 	char t;
@@ -6411,12 +6794,75 @@
 }
 
 /*
+ * Gets proc info in (proc_info_t) given pid. It doesn't return NULL.
+ */
+proc_info_t *
+get_proc_info(pid_t pid)
+{
+	static pid_t saved_pid = 0;
+	static proc_info_t saved_proc_info;
+	static proc_info_t unknown_proc_info = {"<unknown>", "", ""};
+	static psinfo_t pinfo;
+	char path[128];
+	int fd;
+
+	/* hardcode pid = 0 */
+	if (pid == 0) {
+		saved_proc_info.pr_user = "root";
+		saved_proc_info.pr_fname = "sched";
+		saved_proc_info.pr_psargs = "sched";
+		saved_pid = 0;
+		return (&saved_proc_info);
+	}
+
+	if (pid == saved_pid)
+		return (&saved_proc_info);
+	if ((snprintf(path, 128, "/proc/%u/psinfo", (int)pid) > 0) &&
+	    ((fd = open(path, O_RDONLY)) != -1)) {
+		if (read(fd, &pinfo, sizeof (pinfo)) == sizeof (pinfo)) {
+			saved_proc_info.pr_user = get_username(pinfo.pr_uid);
+			saved_proc_info.pr_fname = pinfo.pr_fname;
+			saved_proc_info.pr_psargs = pinfo.pr_psargs;
+			saved_pid = pid;
+			(void) close(fd);
+			return (&saved_proc_info);
+		} else {
+			(void) close(fd);
+		}
+	}
+
+	return (&unknown_proc_info);
+}
+
+/*
+ * Gets username given uid. It doesn't return NULL.
+ */
+static char *
+get_username(uid_t u)
+{
+	static uid_t saved_uid = UINT_MAX;
+	static char  saved_username[128];
+	struct passwd *pw = NULL;
+	if (u == UINT_MAX)
+		return ("<unknown>");
+	if (u == saved_uid && saved_username[0] != '\0')
+		return (saved_username);
+	setpwent();
+	if ((pw = getpwuid(u)) != NULL)
+		(void) strlcpy(saved_username, pw->pw_name, 128);
+	else
+		(void) snprintf(saved_username, 128, "%u", u);
+	saved_uid = u;
+	return (saved_username);
+}
+
+/*
  * print the usage line
  */
 static void
 usage(char *cmdname)
 {
-	(void) fprintf(stderr, "usage: %s [-anv] [-f address_family] "
+	(void) fprintf(stderr, "usage: %s [-anuv] [-f address_family] "
 	    "[-T d|u]\n", cmdname);
 	(void) fprintf(stderr, "       %s [-n] [-f address_family] "
 	    "[-P protocol] [-T d|u] [-g | -p | -s [interval [count]]]\n",
@@ -6453,3 +6899,179 @@
 
 	exit(errcode);
 }
+
+
+/* -------------------UNIX Domain Sockets Report---------------------------- */
+
+
+#define	NO_ADDR		"                                       "
+#define	SO_PAIR		" (socketpair)                          "
+
+static char		*typetoname(t_scalar_t);
+static boolean_t	uds_report_item(struct sockinfo *, boolean_t);
+
+
+static char uds_hdr[] = "\nActive UNIX domain sockets\n";
+
+static char uds_hdr_normal[] =
+" Type       Local Adress                           "
+" Remote Address\n"
+"---------- --------------------------------------- "
+"---------------------------------------\n";
+
+static char uds_hdr_pid[] =
+" Type       User     Pid     Command       "
+" Local Address                         "
+" Remote Address\n"
+"---------- -------- ------ -------------- "
+"--------------------------------------- "
+"---------------------------------------\n";
+static char uds_hdr_pid_verbose[] =
+" Type       User     Pid    Local Address                          "
+" Remote Address                          Command\n"
+"---------- -------- ------ --------------------------------------- "
+"--------------------------------------- --------------\n";
+
+/*
+ * Print a summary of connections related to unix protocols.
+ */
+static void
+uds_report(kstat_ctl_t 	*kc)
+{
+	int		i;
+	kstat_t		*ksp;
+	struct sockinfo	*psi;
+	boolean_t	print_uds_hdr_once = B_TRUE;
+
+	if (kc == NULL) {
+		fail(0, "uds_report: No kstat");
+		exit(3);
+	}
+
+	if ((ksp = kstat_lookup(kc, "sockfs", 0, "sock_unix_list")) ==
+	    (kstat_t *)NULL) {
+		fail(0, "kstat_data_lookup failed\n");
+	}
+
+	if (kstat_read(kc, ksp, NULL) == -1) {
+		fail(0, "kstat_read failed for sock_unix_list\n");
+	}
+
+	if (ksp->ks_ndata == 0) {
+		return;			/* no AF_UNIX sockets found	*/
+	}
+
+	/*
+	 * Having ks_data set with ks_data == NULL shouldn't happen;
+	 * If it does, the sockfs kstat is seriously broken.
+	 */
+	if ((psi = ksp->ks_data) == NULL) {
+		fail(0, "uds_report: no kstat data\n");
+	}
+
+	for (i = 0; i < ksp->ks_ndata; i++) {
+
+		print_uds_hdr_once = uds_report_item(psi, print_uds_hdr_once);
+
+		/* if si_size didn't get filled in, then we're done	*/
+		if (psi->si_size == 0 ||
+		    !IS_P2ALIGNED(psi->si_size, sizeof (psi))) {
+			break;
+		}
+
+		/* point to the next sockinfo in the array */
+		/* LINTED: (note 1) */
+		psi = (struct sockinfo *)(((char *)psi) + psi->si_size);
+	}
+}
+
+static boolean_t
+uds_report_item(struct sockinfo *psi, boolean_t first)
+{
+	int		i = 0;
+	pid_t		*pids;
+	proc_info_t	*pinfo;
+	char		*laddr, *raddr;
+
+	if (first) {
+		(void) printf("%s", uds_hdr);
+		if (Uflag)
+			(void) printf("%s", Vflag?uds_hdr_pid_verbose:
+			    uds_hdr_pid);
+		else
+			(void) printf("%s", uds_hdr_normal);
+
+		first = B_FALSE;
+	}
+
+	pids = psi->si_pids;
+
+	do {
+		pinfo = get_proc_info(*pids);
+		raddr = laddr = NO_ADDR;
+
+		/* Try to fill laddr */
+		if ((psi->si_state & SS_ISBOUND) &&
+		    strlen(psi->si_laddr_sun_path) != 0 &&
+		    psi->si_laddr_soa_len != 0) {
+			if (psi->si_faddr_noxlate) {
+				laddr = SO_PAIR;
+			} else {
+				if (psi->si_laddr_soa_len >
+				    sizeof (psi->si_laddr_family))
+					laddr = psi->si_laddr_sun_path;
+			}
+		}
+
+		/* Try to fill raddr */
+		if ((psi->si_state & SS_ISCONNECTED) &&
+		    strlen(psi->si_faddr_sun_path) != 0 &&
+		    psi->si_faddr_soa_len != 0) {
+
+			if (psi->si_faddr_noxlate) {
+				raddr = SO_PAIR;
+			} else {
+				if (psi->si_faddr_soa_len >
+				    sizeof (psi->si_faddr_family))
+					raddr = psi->si_faddr_sun_path;
+			}
+		}
+
+		if (Uflag && Vflag) {
+			(void) printf("%-10.10s %-8.8s %6u "
+			    "%-39.39s %-39.39s %s\n",
+			    typetoname(psi->si_serv_type), pinfo->pr_user,
+			    (int)*pids, laddr, raddr, pinfo->pr_psargs);
+		} else if (Uflag && (!Vflag)) {
+			(void) printf("%-10.10s %-8.8s %6u %-14.14s"
+			    "%-39.39s %-39.39s\n",
+			    typetoname(psi->si_serv_type), pinfo->pr_user,
+			    (int)*pids, pinfo->pr_fname, laddr, raddr);
+		} else {
+			(void) printf("%-10.10s %s %s\n",
+			    typetoname(psi->si_serv_type), laddr, raddr);
+		}
+
+		i++; pids++;
+	} while (i < psi->si_pn_cnt);
+
+	return (first);
+}
+
+static char *
+typetoname(t_scalar_t type)
+{
+	switch (type) {
+	case T_CLTS:
+		return ("dgram");
+
+	case T_COTS:
+		return ("stream");
+
+	case T_COTS_ORD:
+		return ("stream-ord");
+
+	default:
+		return ("");
+	}
+}
--- old/usr/src/cmd/cmd-inet/usr.bin/netstat/unix.c	2015-12-04 14:19:21.529404185 +0300
+++ /dev/null	2015-12-04 14:19:21.000000000 +0300
@@ -1,243 +0,0 @@
-/*
- * 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 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
-
-/*
- * University Copyright- Copyright (c) 1982, 1986, 1988
- * The Regents of the University of California
- * All Rights Reserved
- *
- * University Acknowledgment- Portions of this document are derived from
- * software developed by the University of California, Berkeley, and its
- * contributors.
- */
-
-/*
- * code for netstat's -k option
- *
- * NOTES:
- * 1. A comment "LINTED: (note 1)" appears before certain lines where
- *    lint would have complained, "pointer cast may result in improper
- *    alignment". These are lines where lint had suspected potential
- *    improper alignment of a data structure; in each such situation
- *    we have relied on the kernel guaranteeing proper alignment.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <string.h>
-#include <kstat.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stream.h>
-#include <sys/tiuser.h>
-#include <sys/socketvar.h>
-#include <sys/sysmacros.h>
-
-static char		*typetoname(t_scalar_t);
-static void		print_kn(kstat_t *);
-static char		*nextstr(char *);
-extern void		fail(int, char *, ...);
-
-#define	NALEN	8			/* nulladdress string length	*/
-
-/*
- * Print a summary of connections related to a unix protocol.
- */
-void
-unixpr(kstat_ctl_t 	*kc)
-{
-	kstat_t		*ksp;
-
-	if (kc == NULL) {	/* sanity check.			*/
-		fail(0, "unixpr: No kstat");
-		exit(3);
-	}
-
-	/* find the sockfs kstat:					*/
-	if ((ksp = kstat_lookup(kc, "sockfs", 0, "sock_unix_list")) ==
-	    (kstat_t *)NULL) {
-		fail(0, "kstat_data_lookup failed\n");
-	}
-
-	if (kstat_read(kc, ksp, NULL) == -1) {
-		fail(0, "kstat_read failed for sock_unix_list\n");
-	}
-
-	print_kn(ksp);
-}
-
-static void
-print_kn(kstat_t *ksp)
-{
-	int		i;
-	struct sockinfo	*psi;		/* ptr to current sockinfo	*/
-	char		*pas;		/* ptr to string-format addrs	*/
-	char		*nullstr;	/* ptr to null string		*/
-	char		*conn_vp;
-	char		*local_vp;
-
-	if (ksp->ks_ndata == 0) {
-		return;			/* no AF_UNIX sockets found	*/
-	}
-
-	/*
-	 * Having ks_data set with ks_data == NULL shouldn't happen;
-	 * If it does, the sockfs kstat is seriously broken.
-	 */
-	if ((psi = ksp->ks_data) == NULL) {
-		fail(0, "print_kn: no kstat data\n");
-	}
-
-	/* set pas to the address strings which are after the sockinfo	*/
-	pas = &((char *)psi)[sizeof (struct sockinfo)];
-
-	/* Create a string of NALEN "0"'s for NULL addresses.		*/
-	if ((nullstr = calloc(1, NALEN)) == NULL) {
-		fail(0, "print_kn: out of memory\n");
-	}
-	(void) memset((void *)nullstr, '0', NALEN);
-
-	(void) printf("\nActive UNIX domain sockets\n");
-	(void) printf("%-8.8s %-10.10s %8.8s %8.8s  "
-	    "Local Addr      Remote Addr\n",
-	    "Address", "Type", "Vnode", "Conn");
-
-	/* for each sockinfo structure, display what we need:		*/
-	for (i = 0; i < ksp->ks_ndata; i++) {
-		/* display sonode's address. 1st string after sockinfo:	*/
-		pas = &(((char *)psi)[sizeof (struct sockinfo)]);
-		(void) printf("%s ", pas);
-
-		(void) printf("%-10.10s ", typetoname(psi->si_serv_type));
-
-		/* laddr.sou_vp: 2nd string after sockinfo:		*/
-		pas = nextstr(pas);
-
-		local_vp = conn_vp = nullstr;
-
-		if ((psi->si_state & SS_ISBOUND) &&
-		    (psi->si_ux_laddr_sou_magic == SOU_MAGIC_EXPLICIT)) {
-			local_vp = pas;
-		}
-
-		/* faddr.sou_vp: 3rd string after sockinfo:		*/
-		pas = nextstr(pas);
-		if ((psi->si_state & SS_ISCONNECTED) &&
-		    (psi->si_ux_faddr_sou_magic == SOU_MAGIC_EXPLICIT)) {
-			conn_vp = pas;
-		}
-
-		(void) printf("%s %s ", local_vp, conn_vp);
-
-		/* laddr.soa_sa: 					*/
-		if ((psi->si_state & SS_ISBOUND) &&
-		    strlen(psi->si_laddr_sun_path) != 0 &&
-		    psi->si_laddr_soa_len != 0) {
-			if (psi->si_faddr_noxlate) {
-				(void) printf(" (socketpair)  ");
-			} else {
-				if (psi->si_laddr_soa_len >
-				    sizeof (psi->si_laddr_family))
-					(void) printf("%s ",
-					    psi->si_laddr_sun_path);
-				else
-					(void) printf("               ");
-			}
-		} else
-			(void) printf("               ");
-
-		/* faddr.soa_sa:					*/
-		if ((psi->si_state & SS_ISCONNECTED) &&
-		    strlen(psi->si_faddr_sun_path) != 0 &&
-		    psi->si_faddr_soa_len != 0) {
-
-			if (psi->si_faddr_noxlate) {
-				(void) printf(" (socketpair)  ");
-			} else {
-				if (psi->si_faddr_soa_len >
-				    sizeof (psi->si_faddr_family))
-					(void) printf("%s ",
-					    psi->si_faddr_sun_path);
-				else
-					(void) printf("               ");
-			}
-		} else
-			(void) printf("               ");
-
-		(void) printf("\n");
-
-		/* if si_size didn't get filled in, then we're done	*/
-		if (psi->si_size == 0 ||
-		    !IS_P2ALIGNED(psi->si_size, sizeof (psi))) {
-			break;
-		}
-
-		/* LINTED: (note 1) */
-		psi = (struct sockinfo *)&(((char *)psi)[psi->si_size]);
-	}
-}
-
-static char *
-typetoname(t_scalar_t type)
-{
-	switch (type) {
-	case T_CLTS:
-		return ("dgram");
-
-	case T_COTS:
-		return ("stream");
-
-	case T_COTS_ORD:
-		return ("stream-ord");
-
-	default:
-		return ("");
-	}
-}
-
-/*
- * nextstr():	find the beginning of a next string.
- *	The sockfs kstat left-justifies each address string, leaving
- *	null's between the strings. Since we don't necessarily know
- *	the sizes of pointers in the kernel, we need to skip over these
- *	nulls in order to get to the start of the next string.
- */
-static char *
-nextstr(char *pas)
-{
-	char *next;
-
-	for (next = &pas[strlen(pas) + 1]; *next == NULL; ) {
-		next++;
-	}
-
-	return (next);
-}
--- old/usr/src/cmd/perl/contrib/Sun/Solaris/Kstat/Kstat.xs	2015-12-04 14:19:21.609474295 +0300
+++ new/usr/src/cmd/perl/contrib/Sun/Solaris/Kstat/Kstat.xs	2015-12-04 14:19:21.619607907 +0300
@@ -62,8 +62,8 @@
  *
  * sockfs:*:sock_unix_list
  * This is stored as an array with one entry per active socket.  Each element
- * is of type struct k_sockinfo.  The ks_ndata and ks_data_size fields are both
- * zero.
+ * is of type struct sockinfo.  ks_ndata is the number of elements of that array
+ * and ks_data_size is the total size of the array.
  *
  * Note that the ks_ndata and ks_data_size of many non-array raw kstats are
  * also incorrect.  The relevant assertions are therefore commented out in the
--- old/usr/src/pkg/manifests/system-header.mf	2015-12-04 14:19:21.886046400 +0300
+++ new/usr/src/pkg/manifests/system-header.mf	2015-12-04 14:19:21.894901488 +0300
@@ -1289,6 +1289,7 @@
 file path=usr/include/sys/pghw.h
 file path=usr/include/sys/physmem.h
 $(i386_ONLY)file path=usr/include/sys/pic.h
+file path=usr/include/sys/pidnode.h
 $(i386_ONLY)file path=usr/include/sys/pit.h
 file path=usr/include/sys/pkp_hash.h
 file path=usr/include/sys/pm.h
--- old/usr/src/uts/common/Makefile.files	2015-12-04 14:19:22.184280085 +0300
+++ new/usr/src/uts/common/Makefile.files	2015-12-04 14:19:22.193239107 +0300
@@ -259,6 +259,7 @@
 		pgrp.o		\
 		pgrpsys.o	\
 		pid.o		\
+		pidnode.o	\
 		pkp_hash.o	\
 		policy.o	\
 		poll.o		\
--- old/usr/src/uts/common/fs/doorfs/door_sys.c	2015-12-04 14:19:22.526185072 +0300
+++ new/usr/src/uts/common/fs/doorfs/door_sys.c	2015-12-04 14:19:22.534105797 +0300
@@ -1784,6 +1784,12 @@
 	setf(fd, fp);
 	dp->d_data.d_desc.d_descriptor = fd;
 
+	/* Add pid to the list associated with that descriptor. */
+	if (fp->f_vnode != NULL)
+		(void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
+		    (intptr_t)curproc->p_pidp->pid_id, FKIOCTL, kcred, NULL,
+		    NULL);
+
 	/* Fill in the attributes */
 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
 		vp = fp->f_vnode;
@@ -2724,7 +2730,7 @@
  */
 static int
 door_results(kthread_t *caller, caddr_t data_ptr, size_t data_size,
-		door_desc_t *desc_ptr, uint_t desc_num)
+    door_desc_t *desc_ptr, uint_t desc_num)
 {
 	door_client_t	*ct = DOOR_CLIENT(caller->t_door);
 	door_upcall_t	*dup = ct->d_upcall;
--- old/usr/src/uts/common/fs/sockfs/sockcommon.c	2015-12-04 14:19:22.829849989 +0300
+++ new/usr/src/uts/common/fs/sockfs/sockcommon.c	2015-12-04 14:19:22.836348260 +0300
@@ -475,6 +475,8 @@
 	    offsetof(struct sonode, so_acceptq_node));
 	list_create(&so->so_acceptq_defer, sizeof (struct sonode),
 	    offsetof(struct sonode, so_acceptq_node));
+	avl_create(&so->so_pid_tree, pid_node_comparator, sizeof (pid_node_t),
+	    offsetof(pid_node_t, pn_ref_link));
 	list_link_init(&so->so_acceptq_node);
 	so->so_acceptq_len	= 0;
 	so->so_backlog		= 0;
@@ -490,6 +492,7 @@
 
 	mutex_init(&so->so_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&so->so_acceptq_lock, NULL, MUTEX_DEFAULT, NULL);
+	mutex_init(&so->so_pid_tree_lock, NULL, MUTEX_DEFAULT, NULL);
 	rw_init(&so->so_fallback_rwlock, NULL, RW_DEFAULT, NULL);
 	cv_init(&so->so_state_cv, NULL, CV_DEFAULT, NULL);
 	cv_init(&so->so_single_cv, NULL, CV_DEFAULT, NULL);
@@ -520,6 +523,7 @@
 
 	list_destroy(&so->so_acceptq_list);
 	list_destroy(&so->so_acceptq_defer);
+	avl_destroy(&so->so_pid_tree);
 	ASSERT(!list_link_active(&so->so_acceptq_node));
 	ASSERT(so->so_listener == NULL);
 
@@ -535,6 +539,7 @@
 
 	mutex_destroy(&so->so_lock);
 	mutex_destroy(&so->so_acceptq_lock);
+	mutex_destroy(&so->so_pid_tree_lock);
 	rw_destroy(&so->so_fallback_rwlock);
 
 	cv_destroy(&so->so_state_cv);
@@ -626,6 +631,7 @@
 sonode_fini(struct sonode *so)
 {
 	vnode_t *vp;
+	pid_node_t *pn;
 
 	ASSERT(so->so_count == 0);
 
@@ -654,6 +660,13 @@
 	if (so->so_filter_top != NULL)
 		sof_sonode_cleanup(so);
 
+	mutex_enter(&so->so_pid_tree_lock);
+	while ((pn = avl_first(&so->so_pid_tree)) != NULL) {
+		avl_remove(&so->so_pid_tree, pn);
+		kmem_free(pn, sizeof (*pn));
+	}
+	mutex_exit(&so->so_pid_tree_lock);
+
 	ASSERT(list_is_empty(&so->so_acceptq_list));
 	ASSERT(list_is_empty(&so->so_acceptq_defer));
 	ASSERT(!list_link_active(&so->so_acceptq_node));
@@ -664,3 +677,44 @@
 	ASSERT(so->so_rcv_head == NULL);
 	ASSERT(so->so_rcv_last_head == NULL);
 }
+
+void
+sonode_insert_pid(struct sonode *so, pid_t pid)
+{
+	pid_node_t	*pn, lookup_pn;
+	avl_index_t	idx_pn;
+
+	lookup_pn.pn_pid = pid;
+	mutex_enter(&so->so_pid_tree_lock);
+	pn = avl_find(&so->so_pid_tree, &lookup_pn, &idx_pn);
+
+	if (pn != NULL) {
+		pn->pn_count++;
+	} else {
+		pn = kmem_zalloc(sizeof (*pn), KM_SLEEP);
+		pn->pn_pid = pid;
+		pn->pn_count = 1;
+		avl_insert(&so->so_pid_tree, pn, idx_pn);
+	}
+	mutex_exit(&so->so_pid_tree_lock);
+}
+
+void
+sonode_remove_pid(struct sonode *so, pid_t pid)
+{
+	pid_node_t *pn, lookup_pn;
+
+	lookup_pn.pn_pid = pid;
+	mutex_enter(&so->so_pid_tree_lock);
+	pn = avl_find(&so->so_pid_tree, &lookup_pn, NULL);
+
+	if (pn != NULL) {
+		if (pn->pn_count > 1) {
+				pn->pn_count--;
+		} else {
+			avl_remove(&so->so_pid_tree, pn);
+			kmem_free(pn, sizeof (*pn));
+		}
+	}
+	mutex_exit(&so->so_pid_tree_lock);
+}
--- old/usr/src/uts/common/fs/sockfs/sockcommon.h	2015-12-04 14:19:23.047477507 +0300
+++ new/usr/src/uts/common/fs/sockfs/sockcommon.h	2015-12-04 14:19:23.057109233 +0300
@@ -163,6 +163,7 @@
 extern int	so_disconnected(sock_upper_handle_t, sock_connid_t, int);
 extern void	so_txq_full(sock_upper_handle_t, boolean_t);
 extern void 	so_opctl(sock_upper_handle_t, sock_opctl_action_t, uintptr_t);
+extern mblk_t	*so_get_sock_pid_mblk(sock_upper_handle_t);
 /* Common misc. functions */
 
 	/* accept queue */
@@ -233,6 +234,8 @@
 extern void 	sonode_init(struct sonode *, struct sockparams *,
     int, int, int, sonodeops_t *);
 extern void	sonode_fini(struct sonode *);
+extern void	sonode_insert_pid(struct sonode *, pid_t);
+extern void	sonode_remove_pid(struct sonode *, pid_t);
 
 /*
  * Event flags to socket_sendsig().
--- old/usr/src/uts/common/fs/sockfs/sockcommon_sops.c	2015-12-04 14:19:23.244418586 +0300
+++ new/usr/src/uts/common/fs/sockfs/sockcommon_sops.c	2015-12-04 14:19:23.253972451 +0300
@@ -37,6 +37,7 @@
 #include <sys/stropts.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
+#include <sys/fcntl.h>
 
 #define	_SUN_TPI_VERSION	2
 #include <sys/tihdr.h>
@@ -357,6 +358,8 @@
 			socket_destroy(nso);
 		} else {
 			*nsop = nso;
+			if (!(curproc->p_flag & SSYS))
+				sonode_insert_pid(nso, curproc->p_pidp->pid_id);
 		}
 	}
 
@@ -1553,6 +1556,44 @@
 	VN_RELE(SOTOV(so));
 }
 
+mblk_t *
+so_get_sock_pid_mblk(sock_upper_handle_t sock_handle)
+{
+	ulong_t sz, n;
+	mblk_t *mblk;
+	pid_node_t *pn;
+	pid_t *pids;
+	conn_pid_info_t *cpi;
+	struct sonode *so = (struct sonode *)sock_handle;
+
+	mutex_enter(&so->so_pid_tree_lock);
+
+	n = avl_numnodes(&so->so_pid_tree);
+	sz = sizeof (conn_pid_info_t);
+	sz += (n > 1) ? ((n - 1) * sizeof (pid_t)) : 0;
+	if ((mblk = allocb(sz, BPRI_HI)) == NULL) {
+		mutex_exit(&so->so_pid_tree_lock);
+		return (NULL);
+	}
+	mblk->b_wptr += sz;
+	cpi = (conn_pid_info_t *)mblk->b_datap->db_base;
+
+	cpi->cpi_magic = CONN_PID_INFO_MGC;
+	cpi->cpi_contents = CONN_PID_INFO_SOC;
+	cpi->cpi_pids_cnt = n;
+	cpi->cpi_tot_size = sz;
+	cpi->cpi_pids[0] = 0;
+
+	if (cpi->cpi_pids_cnt > 0) {
+		pids = cpi->cpi_pids;
+		for (pn = avl_first(&so->so_pid_tree); pn != NULL;
+		    pids++, pn = AVL_NEXT(&so->so_pid_tree, pn))
+			*pids = pn->pn_pid;
+	}
+	mutex_exit(&so->so_pid_tree_lock);
+	return (mblk);
+}
+
 void
 so_zcopy_notify(sock_upper_handle_t sock_handle)
 {
@@ -1953,5 +1994,6 @@
 	so_signal_oob,
 	so_zcopy_notify,
 	so_set_error,
-	so_closed
+	so_closed,
+	so_get_sock_pid_mblk
 };
--- old/usr/src/uts/common/fs/sockfs/sockcommon_vnops.c	2015-12-04 14:19:23.517962248 +0300
+++ new/usr/src/uts/common/fs/sockfs/sockcommon_vnops.c	2015-12-04 14:19:23.529719748 +0300
@@ -123,6 +123,9 @@
 	so->so_count++;
 	mutex_exit(&so->so_lock);
 
+	if (!(curproc->p_flag & SSYS))
+		sonode_insert_pid(so, curproc->p_pidp->pid_id);
+
 	ASSERT(so->so_count != 0);	/* wraparound */
 	ASSERT(vp->v_type == VSOCK);
 
@@ -209,6 +212,22 @@
 
 	ASSERT(vp->v_type == VSOCK);
 
+	switch (cmd) {
+	case F_ASSOCI_PID:
+		if (cr != kcred)
+			return (EPERM);
+		if (!(curproc->p_flag & SSYS))
+			sonode_insert_pid(so, (pid_t)arg);
+		return (0);
+
+	case F_DASSOC_PID:
+		if (cr != kcred)
+			return (EPERM);
+		if (!(curproc->p_flag & SSYS))
+			sonode_remove_pid(so, (pid_t)arg);
+		return (0);
+	}
+
 	return (socket_ioctl(so, cmd, arg, mode, cr, rvalp));
 }
 
--- old/usr/src/uts/common/fs/sockfs/socksubr.c	2015-12-04 14:19:23.731924588 +0300
+++ new/usr/src/uts/common/fs/sockfs/socksubr.c	2015-12-04 14:19:23.741409376 +0300
@@ -113,17 +113,6 @@
 
 extern int modrootloaded;
 
-#define	ADRSTRLEN (2 * sizeof (void *) + 1)
-/*
- * kernel structure for passing the sockinfo data back up to the user.
- * the strings array allows us to convert AF_UNIX addresses into strings
- * with a common method regardless of which n-bit kernel we're running.
- */
-struct k_sockinfo {
-	struct sockinfo	ks_si;
-	char		ks_straddr[3][ADRSTRLEN];
-};
-
 /*
  * Translate from a device pathname (e.g. "/dev/tcp") to a vnode.
  * Returns with the vnode held.
@@ -439,7 +428,7 @@
  */
 static int
 so_ux_lookup(struct sonode *so, struct sockaddr_un *soun, int checkaccess,
-		vnode_t **vpp)
+    vnode_t **vpp)
 {
 	vnode_t		*vp;	/* Underlying filesystem vnode */
 	vnode_t		*rvp;	/* real vnode */
@@ -766,6 +755,16 @@
 		mutex_exit(&fp->f_tlock);
 		setf(fd, fp);
 		*rp++ = fd;
+
+		/*
+		 * Add the current pid to the list associated with this
+		 * descriptor.
+		 */
+		if (fp->f_vnode != NULL)
+			(void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
+			    (intptr_t)curproc->p_pidp->pid_id, FKIOCTL, kcred,
+			    NULL, NULL);
+
 		if (AU_AUDITING())
 			audit_fdrecv(fd, fp);
 		dprint(1, ("fdbuf_extract: [%d] = %d, %p refcnt %d\n",
@@ -1746,10 +1745,13 @@
 static int
 sockfs_update(kstat_t *ksp, int rw)
 {
-	uint_t	nactive = 0;		/* # of active AF_UNIX sockets	*/
+	uint_t	n, nactive = 0;		/* # of active AF_UNIX sockets	*/
+	uint_t	tsze;
 	struct sonode	*so;		/* current sonode on socklist	*/
 	zoneid_t	myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private;
 
+	tsze = 0;
+
 	ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid());
 
 	if (rw == KSTAT_WRITE) {	/* bounce all writes		*/
@@ -1758,11 +1760,19 @@
 
 	for (so = socklist.sl_list; so != NULL; so = SOTOTPI(so)->sti_next_so) {
 		if (so->so_count != 0 && so->so_zoneid == myzoneid) {
+
 			nactive++;
+
+			mutex_enter(&so->so_pid_tree_lock);
+			n = avl_numnodes(&so->so_pid_tree);
+			mutex_exit(&so->so_pid_tree_lock);
+
+			tsze += sizeof (struct sockinfo);
+			tsze += (n > 1) ? ((n - 1) * sizeof (pid_t)) : 0;
 		}
 	}
 	ksp->ks_ndata = nactive;
-	ksp->ks_data_size = nactive * sizeof (struct k_sockinfo);
+	ksp->ks_data_size = tsze;
 
 	return (0);
 }
@@ -1772,11 +1782,15 @@
 {
 	int			ns;	/* # of sonodes we've copied	*/
 	struct sonode		*so;	/* current sonode on socklist	*/
-	struct k_sockinfo	*pksi;	/* where we put sockinfo data	*/
+	struct sockinfo		*psi;	/* where we put sockinfo data	*/
 	t_uscalar_t		sn_len;	/* soa_len			*/
 	zoneid_t		myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private;
 	sotpi_info_t 		*sti;
 
+	uint_t				sze;
+	mblk_t				*mblk;
+	conn_pid_info_t			*cpi;
+
 	ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid());
 
 	ksp->ks_snaptime = gethrtime();
@@ -1789,7 +1803,7 @@
 	 * for each sonode on the socklist, we massage the important
 	 * info into buf, in k_sockinfo format.
 	 */
-	pksi = (struct k_sockinfo *)buf;
+	psi = (struct sockinfo *)buf;
 	ns = 0;
 	for (so = socklist.sl_list; so != NULL; so = SOTOTPI(so)->sti_next_so) {
 		/* only stuff active sonodes and the same zone:		*/
@@ -1797,30 +1811,48 @@
 			continue;
 		}
 
+		mblk = so_get_sock_pid_mblk((sock_upper_handle_t)so);
+		if (mblk == NULL) {
+			continue;
+		}
+		cpi = (conn_pid_info_t *)mblk->b_datap->db_base;
+		sze = sizeof (struct sockinfo);
+		sze += (cpi->cpi_pids_cnt > 1) ?
+		    ((cpi->cpi_pids_cnt - 1) * sizeof (pid_t)) : 0;
+
 		/*
 		 * If the sonode was activated between the update and the
-		 * snapshot, we're done - as this is only a snapshot.
+		 * snapshot, we're done - as this is only a snapshot. We need
+		 * to make sure that we have space for this sockinfo. In the
+		 * time window between the update and the snapshot, the size of
+		 * sockinfo may change, as new pids are added/removed to/from
+		 * the list. We have to take that into consideration and only
+		 * include the sockinfo if we have enough space. That means the
+		 * number of entries we return by snapshot might not equal the
+		 * the number of entries calculated by update.
 		 */
-		if ((caddr_t)(pksi) >= (caddr_t)buf + ksp->ks_data_size) {
+		if (((caddr_t)(psi) + sze) >
+		    ((caddr_t)buf + ksp->ks_data_size)) {
 			break;
 		}
 
 		sti = SOTOTPI(so);
 		/* copy important info into buf:			*/
-		pksi->ks_si.si_size = sizeof (struct k_sockinfo);
-		pksi->ks_si.si_family = so->so_family;
-		pksi->ks_si.si_type = so->so_type;
-		pksi->ks_si.si_flag = so->so_flag;
-		pksi->ks_si.si_state = so->so_state;
-		pksi->ks_si.si_serv_type = sti->sti_serv_type;
-		pksi->ks_si.si_ux_laddr_sou_magic =
+		psi->si_size = sze;
+		psi->si_family = so->so_family;
+		psi->si_type = so->so_type;
+		psi->si_flag = so->so_flag;
+		psi->si_state = so->so_state;
+		psi->si_serv_type = sti->sti_serv_type;
+		psi->si_ux_laddr_sou_magic =
 		    sti->sti_ux_laddr.soua_magic;
-		pksi->ks_si.si_ux_faddr_sou_magic =
+		psi->si_ux_faddr_sou_magic =
 		    sti->sti_ux_faddr.soua_magic;
-		pksi->ks_si.si_laddr_soa_len = sti->sti_laddr.soa_len;
-		pksi->ks_si.si_faddr_soa_len = sti->sti_faddr.soa_len;
-		pksi->ks_si.si_szoneid = so->so_zoneid;
-		pksi->ks_si.si_faddr_noxlate = sti->sti_faddr_noxlate;
+		psi->si_laddr_soa_len = sti->sti_laddr.soa_len;
+		psi->si_faddr_soa_len = sti->sti_faddr.soa_len;
+		psi->si_szoneid = so->so_zoneid;
+		psi->si_faddr_noxlate = sti->sti_faddr_noxlate;
+
 
 		mutex_enter(&so->so_lock);
 
@@ -1828,47 +1860,55 @@
 			ASSERT(sti->sti_laddr_sa->sa_data != NULL);
 			sn_len = sti->sti_laddr_len;
 			ASSERT(sn_len <= sizeof (short) +
-			    sizeof (pksi->ks_si.si_laddr_sun_path));
+			    sizeof (psi->si_laddr_sun_path));
 
-			pksi->ks_si.si_laddr_family =
+			psi->si_laddr_family =
 			    sti->sti_laddr_sa->sa_family;
 			if (sn_len != 0) {
 				/* AF_UNIX socket names are NULL terminated */
-				(void) strncpy(pksi->ks_si.si_laddr_sun_path,
+				(void) strncpy(psi->si_laddr_sun_path,
 				    sti->sti_laddr_sa->sa_data,
-				    sizeof (pksi->ks_si.si_laddr_sun_path));
-				sn_len = strlen(pksi->ks_si.si_laddr_sun_path);
+				    sizeof (psi->si_laddr_sun_path));
+				sn_len = strlen(psi->si_laddr_sun_path);
 			}
-			pksi->ks_si.si_laddr_sun_path[sn_len] = 0;
+			psi->si_laddr_sun_path[sn_len] = 0;
 		}
 
 		if (sti->sti_faddr_sa != NULL) {
 			ASSERT(sti->sti_faddr_sa->sa_data != NULL);
 			sn_len = sti->sti_faddr_len;
 			ASSERT(sn_len <= sizeof (short) +
-			    sizeof (pksi->ks_si.si_faddr_sun_path));
+			    sizeof (psi->si_faddr_sun_path));
 
-			pksi->ks_si.si_faddr_family =
+			psi->si_faddr_family =
 			    sti->sti_faddr_sa->sa_family;
 			if (sn_len != 0) {
-				(void) strncpy(pksi->ks_si.si_faddr_sun_path,
+				(void) strncpy(psi->si_faddr_sun_path,
 				    sti->sti_faddr_sa->sa_data,
-				    sizeof (pksi->ks_si.si_faddr_sun_path));
-				sn_len = strlen(pksi->ks_si.si_faddr_sun_path);
+				    sizeof (psi->si_faddr_sun_path));
+				sn_len = strlen(psi->si_faddr_sun_path);
 			}
-			pksi->ks_si.si_faddr_sun_path[sn_len] = 0;
+			psi->si_faddr_sun_path[sn_len] = 0;
 		}
 
 		mutex_exit(&so->so_lock);
 
-		(void) sprintf(pksi->ks_straddr[0], "%p", (void *)so);
-		(void) sprintf(pksi->ks_straddr[1], "%p",
+		(void) sprintf(psi->si_son_straddr, "%p", (void *)so);
+		(void) sprintf(psi->si_lvn_straddr, "%p",
 		    (void *)sti->sti_ux_laddr.soua_vp);
-		(void) sprintf(pksi->ks_straddr[2], "%p",
+		(void) sprintf(psi->si_fvn_straddr, "%p",
 		    (void *)sti->sti_ux_faddr.soua_vp);
 
+		psi->si_pids[0] = 0;
+		if ((psi->si_pn_cnt = cpi->cpi_pids_cnt) > 0) {
+			(void) memcpy(psi->si_pids, cpi->cpi_pids,
+			    psi->si_pn_cnt * sizeof (pid_t));
+		}
+
+		freemsg(mblk);
+
+		psi = (struct sockinfo *)((caddr_t)psi + psi->si_size);
 		ns++;
-		pksi++;
 	}
 
 	ksp->ks_ndata = ns;
--- old/usr/src/uts/common/inet/ip/ipclassifier.c	2015-12-04 14:19:23.985729994 +0300
+++ new/usr/src/uts/common/inet/ip/ipclassifier.c	2015-12-04 14:19:23.994959435 +0300
@@ -2722,3 +2722,30 @@
 	return (1);
 }
 #endif
+
+mblk_t *
+conn_get_pid_mblk(conn_t *connp)
+{
+	mblk_t *mblk;
+	conn_pid_info_t *cpi;
+
+	if (connp->conn_upper_handle != NULL) {
+		return (*connp->conn_upcalls->su_get_sock_pid_mblk)
+		    (connp->conn_upper_handle);
+	} else if (!IPCL_IS_NONSTR(connp) && connp->conn_rq != NULL &&
+	    connp->conn_rq->q_stream != NULL) {
+		return (sh_get_pid_mblk(connp->conn_rq->q_stream));
+	}
+
+	/* return an empty mblk */
+	if ((mblk = allocb(sizeof (conn_pid_info_t), BPRI_HI)) == NULL)
+		return (NULL);
+	mblk->b_wptr += sizeof (conn_pid_info_t);
+	cpi = (conn_pid_info_t *)mblk->b_datap->db_base;
+	cpi->cpi_magic = CONN_PID_INFO_MGC;
+	cpi->cpi_contents = CONN_PID_INFO_NON;
+	cpi->cpi_pids_cnt = 0;
+	cpi->cpi_tot_size = sizeof (conn_pid_info_t);
+	cpi->cpi_pids[0] = 0;
+	return (mblk);
+}
--- old/usr/src/uts/common/inet/ipclassifier.h	2015-12-04 14:19:24.243297587 +0300
+++ new/usr/src/uts/common/inet/ipclassifier.h	2015-12-04 14:19:24.252744729 +0300
@@ -729,6 +729,7 @@
 extern void ip_free_helper_stream(conn_t *);
 extern int	ip_helper_stream_setup(queue_t *, dev_t *, int, int,
     cred_t *, boolean_t);
+extern mblk_t *conn_get_pid_mblk(conn_t *);
 
 #ifdef	__cplusplus
 }
--- old/usr/src/uts/common/inet/mib2.h	2015-12-04 14:19:24.462413973 +0300
+++ new/usr/src/uts/common/inet/mib2.h	2015-12-04 14:19:24.474135035 +0300
@@ -185,6 +185,7 @@
  * There can be one of each of these tables per transport (MIB2_* above).
  */
 #define	EXPER_XPORT_MLP		105	/* transportMLPEntry */
+#define	EXPER_XPORT_PROC_INFO	106	/* conn_pid_node entry */
 
 /* Old names retained for compatibility */
 #define	MIB2_IP_20	MIB2_IP_ADDR
--- old/usr/src/uts/common/inet/sctp/sctp_snmp.c	2015-12-04 14:19:24.741659337 +0300
+++ new/usr/src/uts/common/inet/sctp/sctp_snmp.c	2015-12-04 14:19:24.750355269 +0300
@@ -528,6 +528,9 @@
 	mblk_t			*mp_conn_ctl = NULL;
 	mblk_t			*mp_conn_data;
 	mblk_t			*mp_conn_tail = NULL;
+	mblk_t			*mp_pidnode_ctl = NULL;
+	mblk_t			*mp_pidnode_data;
+	mblk_t			*mp_pidnode_tail = NULL;
 	mblk_t			*mp_local_ctl = NULL;
 	mblk_t			*mp_local_data;
 	mblk_t			*mp_local_tail = NULL;
@@ -560,23 +563,27 @@
 	 */
 	mp_ret = copymsg(mpctl);
 	mp_conn_ctl = copymsg(mpctl);
+	mp_pidnode_ctl = copymsg(mpctl);
 	mp_local_ctl = copymsg(mpctl);
 	mp_rem_ctl = copymsg(mpctl);
 	mp_attr_ctl = copymsg(mpctl);
 
 	mpdata = mpctl->b_cont;
 
-	if (mp_conn_ctl == NULL || mp_local_ctl == NULL ||
-	    mp_rem_ctl == NULL || mp_attr_ctl == NULL || mpdata == NULL) {
+	if (mp_conn_ctl == NULL || mp_pidnode_ctl == NULL ||
+	    mp_local_ctl == NULL || mp_rem_ctl == NULL || mp_attr_ctl == NULL ||
+	    mpdata == NULL) {
 		freemsg(mp_attr_ctl);
 		freemsg(mp_rem_ctl);
 		freemsg(mp_local_ctl);
+		freemsg(mp_pidnode_ctl);
 		freemsg(mp_conn_ctl);
 		freemsg(mp_ret);
 		freemsg(mpctl);
 		return (NULL);
 	}
 	mp_conn_data = mp_conn_ctl->b_cont;
+	mp_pidnode_data = mp_pidnode_ctl->b_cont;
 	mp_local_data = mp_local_ctl->b_cont;
 	mp_rem_data = mp_rem_ctl->b_cont;
 	mp_attr_data = mp_attr_ctl->b_cont;
@@ -803,6 +810,13 @@
 		sce.sctpConnEntryInfo.ce_mss = sctp->sctp_mss;
 		(void) snmp_append_data2(mp_conn_data, &mp_conn_tail,
 		    (char *)&sce, sizeof (sce));
+
+		(void) snmp_append_data2(mp_pidnode_data, &mp_pidnode_tail,
+		    (char *)&sce, sizeof (sce));
+
+		(void) snmp_append_mblk2(mp_pidnode_data, &mp_pidnode_tail,
+		    conn_get_pid_mblk(connp));
+
 		mlp.tme_connidx = idx++;
 		if (needattr)
 			(void) snmp_append_data2(mp_attr_ctl->b_cont,
@@ -833,6 +847,14 @@
 	optp->len = msgdsize(mp_conn_data);
 	qreply(q, mp_conn_ctl);
 
+	/* table of EXPER_XPORT_PROC_INFO */
+	optp = (struct opthdr *)&mp_pidnode_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_SCTP;
+	optp->name = EXPER_XPORT_PROC_INFO;
+	optp->len = msgdsize(mp_pidnode_data);
+	qreply(q, mp_pidnode_ctl);
+
 	/* assoc local address table */
 	optp = (struct opthdr *)&mp_local_ctl->b_rptr[
 	    sizeof (struct T_optmgmt_ack)];
--- old/usr/src/uts/common/inet/snmpcom.c	2015-12-04 14:19:24.975591329 +0300
+++ new/usr/src/uts/common/inet/snmpcom.c	2015-12-04 14:19:24.984338496 +0300
@@ -107,6 +107,17 @@
 	return (1);
 }
 
+int
+snmp_append_mblk(mblk_t *mpdata, mblk_t *mblk)
+{
+	if (!mpdata || !mblk)
+		return (0);
+	while (mpdata->b_cont)
+		mpdata = mpdata->b_cont;
+	mpdata->b_cont = mblk;
+	return (1);
+}
+
 /*
  * Need a form which avoids O(n^2) behavior locating the end of the
  * chain every time.  This is it.
@@ -133,6 +144,21 @@
 	return (1);
 }
 
+int
+snmp_append_mblk2(mblk_t *mpdata, mblk_t **last_mpp, mblk_t *mblk)
+{
+	if (!mpdata || !mblk)
+		return (0);
+	if (*last_mpp == NULL) {
+		while (mpdata->b_cont)
+			mpdata = mpdata->b_cont;
+		*last_mpp = mpdata;
+	}
+	(*last_mpp)->b_cont = mblk;
+	*last_mpp = (*last_mpp)->b_cont;
+	return (1);
+}
+
 /*
  * SNMP requests are issued using putmsg() on a stream containing all
  * relevant modules.  The ctl part contains a O_T_OPTMGMT_REQ message,
--- old/usr/src/uts/common/inet/snmpcom.h	2015-12-04 14:19:25.169588750 +0300
+++ new/usr/src/uts/common/inet/snmpcom.h	2015-12-04 14:19:25.175062559 +0300
@@ -37,8 +37,11 @@
 typedef int (*snmp_getf_t)(queue_t *, mblk_t *, int, boolean_t);
 
 extern int	snmp_append_data(mblk_t *mpdata, char *blob, int len);
+extern int	snmp_append_mblk(mblk_t *mpdata, mblk_t *mblk);
 extern int	snmp_append_data2(mblk_t *mpdata, mblk_t **last_mpp,
 		    char *blob, int len);
+extern int	snmp_append_mblk2(mblk_t *mpdata, mblk_t **last_mpp,
+		    mblk_t *mblk);
 
 extern boolean_t	snmpcom_req(queue_t *q, mblk_t *mp,
     snmp_setf_t setfn, snmp_getf_t getfn, cred_t *cr);
--- old/usr/src/uts/common/inet/sockmods/socksctp.c	2015-12-04 14:19:25.364120191 +0300
+++ new/usr/src/uts/common/inet/sockmods/socksctp.c	2015-12-04 14:19:25.369572765 +0300
@@ -30,6 +30,7 @@
 #include <sys/buf.h>
 #include <sys/vfs.h>
 #include <sys/vnode.h>
+#include <sys/fcntl.h>
 #include <sys/debug.h>
 #include <sys/errno.h>
 #include <sys/stropts.h>
@@ -106,6 +107,7 @@
 static void sctp_assoc_xmitted(sock_upper_handle_t, boolean_t);
 static void sctp_assoc_properties(sock_upper_handle_t,
     struct sock_proto_props *);
+static mblk_t *sctp_get_sock_pid_mblk(sock_upper_handle_t);
 
 sonodeops_t sosctp_sonodeops = {
 	sosctp_init,			/* sop_init	*/
@@ -168,6 +170,9 @@
 	sctp_assoc_xmitted,
 	NULL,			/* su_recv_space */
 	NULL,			/* su_signal_oob */
+	NULL,			/* su_set_error */
+	NULL,			/* su_closed */
+	sctp_get_sock_pid_mblk
 };
 
 /* ARGSUSED */
@@ -1773,6 +1778,13 @@
 		mutex_exit(&nfp->f_tlock);
 		setf(nfd, nfp);
 
+		/* Add pid to the list associated with that socket. */
+		if (nfp->f_vnode != NULL) {
+			(void) VOP_IOCTL(nfp->f_vnode, F_ASSOCI_PID,
+			    (intptr_t)curproc->p_pidp->pid_id, FKIOCTL, kcred,
+			    NULL, NULL);
+		}
+
 		mutex_enter(&so->so_lock);
 
 		sosctp_assoc_move(ss, SOTOSSO(nso), ssa);
@@ -2230,3 +2242,17 @@
 	}
 	mutex_exit(&so->so_lock);
 }
+
+static mblk_t *
+sctp_get_sock_pid_mblk(sock_upper_handle_t handle)
+{
+	struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
+	struct sonode *so;
+
+	if (ssa->ssa_type == SOSCTP_ASSOC)
+		so = &ssa->ssa_sonode->ss_so;
+	else
+		so = &((struct sctp_sonode *)handle)->ss_so;
+
+	return (so_get_sock_pid_mblk((sock_upper_handle_t)so));
+}
--- old/usr/src/uts/common/inet/tcp/tcp_stats.c	2015-12-04 14:19:25.625339899 +0300
+++ new/usr/src/uts/common/inet/tcp/tcp_stats.c	2015-12-04 14:19:25.633202132 +0300
@@ -30,6 +30,13 @@
 #include <sys/tsol/tnet.h>
 #include <sys/kstat.h>
 
+#include <sys/strsun.h>
+#include <sys/stropts.h>
+#include <sys/strsubr.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/uio.h>
+
 #include <inet/common.h>
 #include <inet/ip.h>
 #include <inet/tcp.h>
@@ -97,10 +104,14 @@
 	mblk_t			*mp_conn_tail;
 	mblk_t			*mp_attr_ctl = NULL;
 	mblk_t			*mp_attr_tail;
+	mblk_t			*mp_pidnode_ctl = NULL;
+	mblk_t			*mp_pidnode_tail;
 	mblk_t			*mp6_conn_ctl = NULL;
 	mblk_t			*mp6_conn_tail;
 	mblk_t			*mp6_attr_ctl = NULL;
 	mblk_t			*mp6_attr_tail;
+	mblk_t			*mp6_pidnode_ctl = NULL;
+	mblk_t			*mp6_pidnode_tail;
 	struct opthdr		*optp;
 	mib2_tcpConnEntry_t	tce;
 	mib2_tcp6ConnEntry_t	tce6;
@@ -127,12 +138,16 @@
 	    (mpdata = mpctl->b_cont) == NULL ||
 	    (mp_conn_ctl = copymsg(mpctl)) == NULL ||
 	    (mp_attr_ctl = copymsg(mpctl)) == NULL ||
+	    (mp_pidnode_ctl = copymsg(mpctl)) == NULL ||
 	    (mp6_conn_ctl = copymsg(mpctl)) == NULL ||
-	    (mp6_attr_ctl = copymsg(mpctl)) == NULL) {
+	    (mp6_attr_ctl = copymsg(mpctl)) == NULL ||
+	    (mp6_pidnode_ctl = copymsg(mpctl)) == NULL) {
 		freemsg(mp_conn_ctl);
 		freemsg(mp_attr_ctl);
+		freemsg(mp_pidnode_ctl);
 		freemsg(mp6_conn_ctl);
 		freemsg(mp6_attr_ctl);
+		freemsg(mp6_pidnode_ctl);
 		freemsg(mpctl);
 		freemsg(mp2ctl);
 		return (NULL);
@@ -166,6 +181,7 @@
 
 	v4_conn_idx = v6_conn_idx = 0;
 	mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
+	mp_pidnode_tail = mp6_pidnode_tail = NULL;
 
 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
 		ipst = tcps->tcps_netstack->netstack_ip;
@@ -281,6 +297,12 @@
 			(void) snmp_append_data2(mp6_conn_ctl->b_cont,
 			    &mp6_conn_tail, (char *)&tce6, tce6_size);
 
+			(void) snmp_append_data2(mp6_pidnode_ctl->b_cont,
+			    &mp6_pidnode_tail, (char *)&tce6, tce6_size);
+
+			(void) snmp_append_mblk2(mp6_pidnode_ctl->b_cont,
+			    &mp6_pidnode_tail, conn_get_pid_mblk(connp));
+
 			mlp.tme_connidx = v6_conn_idx++;
 			if (needattr)
 				(void) snmp_append_data2(mp6_attr_ctl->b_cont,
@@ -348,6 +370,12 @@
 				(void) snmp_append_data2(mp_conn_ctl->b_cont,
 				    &mp_conn_tail, (char *)&tce, tce_size);
 
+				(void) snmp_append_data2(mp_pidnode_ctl->b_cont,
+				    &mp_pidnode_tail, (char *)&tce, tce_size);
+
+				(void) snmp_append_mblk2(mp_pidnode_ctl->b_cont,
+				    &mp_pidnode_tail, conn_get_pid_mblk(connp));
+
 				mlp.tme_connidx = v4_conn_idx++;
 				if (needattr)
 					(void) snmp_append_data2(
@@ -417,6 +445,29 @@
 		freemsg(mp6_attr_ctl);
 	else
 		qreply(q, mp6_attr_ctl);
+
+	/* table of EXPER_XPORT_PROC_INFO  ipv4 */
+	optp = (struct opthdr *)&mp_pidnode_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_TCP;
+	optp->name = EXPER_XPORT_PROC_INFO;
+	optp->len = msgdsize(mp_pidnode_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp_pidnode_ctl);
+	else
+		qreply(q, mp_pidnode_ctl);
+
+	/* table of EXPER_XPORT_PROC_INFO  ipv6 */
+	optp = (struct opthdr *)&mp6_pidnode_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_TCP6;
+	optp->name = EXPER_XPORT_PROC_INFO;
+	optp->len = msgdsize(mp6_pidnode_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp6_pidnode_ctl);
+	else
+		qreply(q, mp6_pidnode_ctl);
+
 	return (mp2ctl);
 }
 
--- old/usr/src/uts/common/inet/udp/udp_stats.c	2015-12-04 14:19:25.852342784 +0300
+++ new/usr/src/uts/common/inet/udp/udp_stats.c	2015-12-04 14:19:25.862496802 +0300
@@ -53,12 +53,16 @@
 	mblk_t			*mpdata;
 	mblk_t			*mp_conn_ctl;
 	mblk_t			*mp_attr_ctl;
+	mblk_t			*mp_pidnode_ctl;
 	mblk_t			*mp6_conn_ctl;
 	mblk_t			*mp6_attr_ctl;
+	mblk_t			*mp6_pidnode_ctl;
 	mblk_t			*mp_conn_tail;
 	mblk_t			*mp_attr_tail;
+	mblk_t			*mp_pidnode_tail;
 	mblk_t			*mp6_conn_tail;
 	mblk_t			*mp6_attr_tail;
+	mblk_t			*mp6_pidnode_tail;
 	struct opthdr		*optp;
 	mib2_udpEntry_t		ude;
 	mib2_udp6Entry_t	ude6;
@@ -78,7 +82,6 @@
 	mib2_udp_t		udp_mib;
 	size_t			udp_mib_size, ude_size, ude6_size;
 
-
 	/*
 	 * make a copy of the original message
 	 */
@@ -89,11 +92,16 @@
 	    (mpdata = mpctl->b_cont) == NULL ||
 	    (mp_conn_ctl = copymsg(mpctl)) == NULL ||
 	    (mp_attr_ctl = copymsg(mpctl)) == NULL ||
+	    (mp_pidnode_ctl = copymsg(mpctl)) == NULL ||
 	    (mp6_conn_ctl = copymsg(mpctl)) == NULL ||
-	    (mp6_attr_ctl = copymsg(mpctl)) == NULL) {
+	    (mp6_attr_ctl = copymsg(mpctl)) == NULL ||
+	    (mp6_pidnode_ctl = copymsg(mpctl)) == NULL) {
 		freemsg(mp_conn_ctl);
 		freemsg(mp_attr_ctl);
+		freemsg(mp_pidnode_ctl);
 		freemsg(mp6_conn_ctl);
+		freemsg(mp6_attr_ctl);
+		freemsg(mp6_pidnode_ctl);
 		freemsg(mpctl);
 		freemsg(mp2ctl);
 		return (0);
@@ -135,6 +143,7 @@
 	qreply(q, mpctl);
 
 	mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
+	mp_pidnode_tail = mp6_pidnode_tail = NULL;
 	v4_conn_idx = v6_conn_idx = 0;
 
 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
@@ -249,6 +258,13 @@
 
 				(void) snmp_append_data2(mp_conn_ctl->b_cont,
 				    &mp_conn_tail, (char *)&ude, ude_size);
+
+				(void) snmp_append_data2(mp_pidnode_ctl->b_cont,
+				    &mp_pidnode_tail, (char *)&ude, ude_size);
+
+				(void) snmp_append_mblk2(mp_pidnode_ctl->b_cont,
+				    &mp_pidnode_tail, conn_get_pid_mblk(connp));
+
 				mlp.tme_connidx = v4_conn_idx++;
 				if (needattr)
 					(void) snmp_append_data2(
@@ -292,6 +308,15 @@
 
 				(void) snmp_append_data2(mp6_conn_ctl->b_cont,
 				    &mp6_conn_tail, (char *)&ude6, ude6_size);
+
+				(void) snmp_append_data2(
+				    mp6_pidnode_ctl->b_cont, &mp6_pidnode_tail,
+				    (char *)&ude6, ude6_size);
+
+				(void) snmp_append_mblk2(
+				    mp6_pidnode_ctl->b_cont, &mp6_pidnode_tail,
+				    conn_get_pid_mblk(connp));
+
 				mlp.tme_connidx = v6_conn_idx++;
 				if (needattr)
 					(void) snmp_append_data2(
@@ -321,6 +346,17 @@
 	else
 		qreply(q, mp_attr_ctl);
 
+	/* table of EXPER_XPORT_PROC_INFO ipv4 */
+	optp = (struct opthdr *)&mp_pidnode_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_UDP;
+	optp->name = EXPER_XPORT_PROC_INFO;
+	optp->len = msgdsize(mp_pidnode_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp_pidnode_ctl);
+	else
+		qreply(q, mp_pidnode_ctl);
+
 	/* IPv6 UDP endpoints */
 	optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
 	    sizeof (struct T_optmgmt_ack)];
@@ -340,6 +376,17 @@
 	else
 		qreply(q, mp6_attr_ctl);
 
+	/* table of EXPER_XPORT_PROC_INFO ipv6 */
+	optp = (struct opthdr *)&mp6_pidnode_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_UDP6;
+	optp->name = EXPER_XPORT_PROC_INFO;
+	optp->len = msgdsize(mp6_pidnode_ctl->b_cont);
+	if (optp->len == 0)
+		freemsg(mp6_pidnode_ctl);
+	else
+		qreply(q, mp6_pidnode_ctl);
+
 	return (mp2ctl);
 }
 
--- old/usr/src/uts/common/os/fio.c	2015-12-04 14:19:26.062756794 +0300
+++ new/usr/src/uts/common/os/fio.c	2015-12-04 14:19:26.072260233 +0300
@@ -838,11 +838,14 @@
  * Duplicate all file descriptors across a fork.
  */
 void
-flist_fork(uf_info_t *pfip, uf_info_t *cfip)
+flist_fork(proc_t *pp, proc_t *cp)
 {
 	int fd, nfiles;
 	uf_entry_t *pufp, *cufp;
 
+	uf_info_t *pfip = P_FINFO(pp);
+	uf_info_t *cfip = P_FINFO(cp);
+
 	mutex_init(&cfip->fi_lock, NULL, MUTEX_DEFAULT, NULL);
 	cfip->fi_rlist = NULL;
 
@@ -860,6 +863,13 @@
 		cufp->uf_alloc = pufp->uf_alloc;
 		cufp->uf_flag = pufp->uf_flag;
 		cufp->uf_busy = pufp->uf_busy;
+
+		if (cufp->uf_file != NULL && cufp->uf_file->f_vnode != NULL) {
+			(void) VOP_IOCTL(cufp->uf_file->f_vnode, F_ASSOCI_PID,
+			    (intptr_t)cp->p_pidp->pid_id, FKIOCTL, kcred,
+			    NULL, NULL);
+		}
+
 		if (pufp->uf_file == NULL) {
 			ASSERT(pufp->uf_flag == 0);
 			if (pufp->uf_busy) {
@@ -945,6 +955,11 @@
 	offset = fp->f_offset;
 
 	vp = fp->f_vnode;
+	if (vp != NULL) {
+		(void) VOP_IOCTL(vp, F_DASSOC_PID,
+		    (intptr_t)(ttoproc(curthread)->p_pidp->pid_id), FKIOCTL,
+		    kcred, NULL, NULL);
+	}
 
 	error = VOP_CLOSE(vp, flag, count, offset, fp->f_cred, NULL);
 
--- old/usr/src/uts/common/os/fork.c	2015-12-04 14:19:26.322215462 +0300
+++ new/usr/src/uts/common/os/fork.c	2015-12-04 14:19:26.332644888 +0300
@@ -1189,7 +1189,7 @@
 	 */
 	uarea = PTOU(cp);
 	bcopy(PTOU(pp), uarea, sizeof (*uarea));
-	flist_fork(P_FINFO(pp), P_FINFO(cp));
+	flist_fork(pp, cp);
 
 	gethrestime(&uarea->u_start);
 	uarea->u_ticks = ddi_get_lbolt();
--- /dev/null	2015-12-04 14:19:26.000000000 +0300
+++ new/usr/src/uts/common/os/pidnode.c	2015-12-04 14:19:26.624789641 +0300
@@ -0,0 +1,38 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Mohamed A. Khalfella <khalfella@gmail.com>
+ */
+
+/*
+ * General pidnode routines are stored in this file.
+ */
+
+#include <sys/pidnode.h>
+
+
+/*
+ * Compare two pid_node_t elements. Used by AVL trees.
+ */
+
+int
+pid_node_comparator(const void *l, const void *r)
+{
+	const pid_node_t *li = l;
+	const pid_node_t *ri = r;
+
+	if (li->pn_pid > ri->pn_pid)
+		return (1);
+	if (li->pn_pid < ri->pn_pid)
+		return (-1);
+	return (0);
+}
--- old/usr/src/uts/common/os/streamio.c	2015-12-04 14:19:26.723664276 +0300
+++ new/usr/src/uts/common/os/streamio.c	2015-12-04 14:19:26.729925490 +0300
@@ -78,6 +78,7 @@
 #include <sys/dld.h>
 #include <sys/zone.h>
 #include <c2/audit.h>
+#include <sys/fcntl.h>
 
 /*
  * This define helps improve the readability of streams code while
@@ -143,6 +144,7 @@
 static void strcleanall(struct vnode *);
 static int strwsrv(queue_t *);
 static int strdocmd(struct stdata *, struct strcmd *, cred_t *);
+static boolean_t is_xti_str(const struct stdata *);
 
 /*
  * qinit and module_info structures for stream head read and write queues
@@ -397,6 +399,14 @@
 	STREAM(qp) = STREAM(_WR(qp)) = stp;
 	vp->v_stream = stp;
 	mutex_exit(&vp->v_lock);
+
+	/*
+	 * If this is not a system process, then add it to
+	 * the list associated with the stream head.
+	 */
+	if (!(curproc->p_flag & SSYS) && is_xti_str(stp))
+		sh_insert_pid(stp, curproc->p_pidp->pid_id);
+
 	if (vp->v_type == VFIFO) {
 		stp->sd_flag |= OLDNDELAY;
 		/*
@@ -5683,6 +5693,22 @@
 	case FIONBIO:
 	case FIOASYNC:
 		return (0);	/* handled by the upper layer */
+	case F_ASSOCI_PID:
+	{
+		if (crp != kcred)
+			return (EPERM);
+		if (is_xti_str(stp))
+			sh_insert_pid(stp, (pid_t)arg);
+		return (0);
+	}
+	case F_DASSOC_PID:
+	{
+		if (crp != kcred)
+			return (EPERM);
+		if (is_xti_str(stp))
+			sh_remove_pid(stp, (pid_t)arg);
+		return (0);
+	}
 	}
 }
 
@@ -8635,3 +8661,33 @@
 		}
 	return (B_FALSE);
 }
+
+/*
+ * Check whether a stream is an XTI stream or not.
+ */
+static boolean_t
+is_xti_str(const struct stdata *stp)
+{
+	struct devnames *dnp;
+	vnode_t *vn;
+	major_t major;
+	if ((vn = stp->sd_vnode) != NULL && vn->v_type == VCHR &&
+	    vn->v_rdev != 0) {
+		major = getmajor(vn->v_rdev);
+		dnp = (major != DDI_MAJOR_T_NONE && major >= 0 &&
+		    major < devcnt) ? &devnamesp[major] : NULL;
+		if (dnp != NULL && dnp->dn_name != NULL &&
+		    (strcmp(dnp->dn_name, "ip") == 0 ||
+		    strcmp(dnp->dn_name, "tcp") == 0 ||
+		    strcmp(dnp->dn_name, "udp") == 0 ||
+		    strcmp(dnp->dn_name, "icmp") == 0 ||
+		    strcmp(dnp->dn_name, "tl") == 0 ||
+		    strcmp(dnp->dn_name, "ip6") == 0 ||
+		    strcmp(dnp->dn_name, "tcp6") == 0 ||
+		    strcmp(dnp->dn_name, "udp6") == 0 ||
+		    strcmp(dnp->dn_name, "icmp6") == 0)) {
+			return (B_TRUE);
+		}
+	}
+	return (B_FALSE);
+}
--- old/usr/src/uts/common/os/strsubr.c	2015-12-04 14:19:27.175276791 +0300
+++ new/usr/src/uts/common/os/strsubr.c	2015-12-04 14:19:27.182295015 +0300
@@ -651,11 +651,14 @@
 	mutex_init(&stp->sd_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&stp->sd_reflock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&stp->sd_qlock, NULL, MUTEX_DEFAULT, NULL);
+	mutex_init(&stp->sd_pid_tree_lock, NULL, MUTEX_DEFAULT, NULL);
 	cv_init(&stp->sd_monitor, NULL, CV_DEFAULT, NULL);
 	cv_init(&stp->sd_iocmonitor, NULL, CV_DEFAULT, NULL);
 	cv_init(&stp->sd_refmonitor, NULL, CV_DEFAULT, NULL);
 	cv_init(&stp->sd_qcv, NULL, CV_DEFAULT, NULL);
 	cv_init(&stp->sd_zcopy_wait, NULL, CV_DEFAULT, NULL);
+	avl_create(&stp->sd_pid_tree, pid_node_comparator, sizeof (pid_node_t),
+	    offsetof(pid_node_t, pn_ref_link));
 	stp->sd_wrq = NULL;
 
 	return (0);
@@ -670,11 +673,13 @@
 	mutex_destroy(&stp->sd_lock);
 	mutex_destroy(&stp->sd_reflock);
 	mutex_destroy(&stp->sd_qlock);
+	mutex_destroy(&stp->sd_pid_tree_lock);
 	cv_destroy(&stp->sd_monitor);
 	cv_destroy(&stp->sd_iocmonitor);
 	cv_destroy(&stp->sd_refmonitor);
 	cv_destroy(&stp->sd_qcv);
 	cv_destroy(&stp->sd_zcopy_wait);
+	avl_destroy(&stp->sd_pid_tree);
 }
 
 /*
@@ -949,7 +954,7 @@
  */
 static void
 dosendsig(proc_t *proc, int events, int sevent, k_siginfo_t *info,
-	uchar_t band, int error)
+    uchar_t band, int error)
 {
 	ASSERT(MUTEX_HELD(&proc->p_lock));
 
@@ -2349,7 +2354,7 @@
  */
 int
 devflg_to_qflag(struct streamtab *stp, uint32_t devflag, uint32_t *qflagp,
-	uint32_t *sqtypep)
+    uint32_t *sqtypep)
 {
 	uint32_t qflag = 0;
 	uint32_t sqtype = 0;
@@ -3316,6 +3321,8 @@
 void
 shfree(stdata_t *stp)
 {
+	pid_node_t *pn;
+
 	ASSERT(MUTEX_NOT_HELD(&stp->sd_lock));
 
 	stp->sd_wrq = NULL;
@@ -3339,9 +3346,94 @@
 	ASSERT(stp->sd_qhead == NULL);
 	ASSERT(stp->sd_qtail == NULL);
 	ASSERT(stp->sd_nqueues == 0);
+
+	mutex_enter(&stp->sd_pid_tree_lock);
+	while ((pn = avl_first(&stp->sd_pid_tree)) != NULL) {
+		avl_remove(&stp->sd_pid_tree, pn);
+		kmem_free(pn, sizeof (*pn));
+	}
+	mutex_exit(&stp->sd_pid_tree_lock);
+
 	kmem_cache_free(stream_head_cache, stp);
 }
 
+void
+sh_insert_pid(struct stdata *stp, pid_t pid)
+{
+	pid_node_t *pn, lookup_pn;
+	avl_index_t idx_pn;
+
+	lookup_pn.pn_pid = pid;
+	mutex_enter(&stp->sd_pid_tree_lock);
+	pn = avl_find(&stp->sd_pid_tree, &lookup_pn, &idx_pn);
+
+	if (pn != NULL) {
+		pn->pn_count++;
+	} else {
+		pn = kmem_zalloc(sizeof (*pn), KM_SLEEP);
+		pn->pn_pid = pid;
+		pn->pn_count = 1;
+		avl_insert(&stp->sd_pid_tree, pn, idx_pn);
+	}
+	mutex_exit(&stp->sd_pid_tree_lock);
+}
+
+void
+sh_remove_pid(struct stdata *stp, pid_t pid)
+{
+	pid_node_t *pn, lookup_pn;
+
+	lookup_pn.pn_pid = pid;
+	mutex_enter(&stp->sd_pid_tree_lock);
+	pn = avl_find(&stp->sd_pid_tree, &lookup_pn, NULL);
+
+	if (pn != NULL) {
+		if (pn->pn_count > 1) {
+			pn->pn_count--;
+		} else {
+			avl_remove(&stp->sd_pid_tree, pn);
+			kmem_free(pn, sizeof (*pn));
+		}
+	}
+	mutex_exit(&stp->sd_pid_tree_lock);
+}
+
+mblk_t *
+sh_get_pid_mblk(struct stdata *stp)
+{
+	mblk_t *mblk;
+	ulong_t sz, n;
+	pid_t *pids;
+	pid_node_t *pn;
+	conn_pid_info_t *cpi;
+
+	mutex_enter(&stp->sd_pid_tree_lock);
+
+	n = avl_numnodes(&stp->sd_pid_tree);
+	sz = sizeof (conn_pid_info_t);
+	sz += (n > 1) ? ((n - 1) * sizeof (pid_t)) : 0;
+	if ((mblk = allocb(sz, BPRI_HI)) == NULL) {
+		mutex_exit(&stp->sd_pid_tree_lock);
+		return (NULL);
+	}
+	mblk->b_wptr += sz;
+	cpi = (conn_pid_info_t *)mblk->b_datap->db_base;
+	cpi->cpi_magic = CONN_PID_INFO_MGC;
+	cpi->cpi_contents = CONN_PID_INFO_XTI;
+	cpi->cpi_pids_cnt = n;
+	cpi->cpi_tot_size = sz;
+	cpi->cpi_pids[0] = 0;
+
+	if (cpi->cpi_pids_cnt > 0) {
+		pids = cpi->cpi_pids;
+		for (pn = avl_first(&stp->sd_pid_tree); pn != NULL;
+		    pids++, pn = AVL_NEXT(&stp->sd_pid_tree, pn))
+			*pids = pn->pn_pid;
+	}
+	mutex_exit(&stp->sd_pid_tree_lock);
+	return (mblk);
+}
+
 /*
  * Allocate a pair of queues and a syncq for the pair
  */
@@ -8085,8 +8177,8 @@
 }
 
 void
-strsetrputhooks(vnode_t *vp, uint_t flags,
-		msgfunc_t protofunc, msgfunc_t miscfunc)
+strsetrputhooks(vnode_t *vp, uint_t flags, msgfunc_t protofunc,
+    msgfunc_t miscfunc)
 {
 	struct stdata *stp = vp->v_stream;
 
--- old/usr/src/uts/common/sys/Makefile	2015-12-04 14:19:27.627898386 +0300
+++ new/usr/src/uts/common/sys/Makefile	2015-12-04 14:19:27.633356322 +0300
@@ -136,6 +136,7 @@
 	crc32.h			\
 	cred.h			\
 	cred_impl.h		\
+	pidnode.h		\
 	crtctl.h		\
 	cryptmod.h		\
 	csiioctl.h		\
--- old/usr/src/uts/common/sys/fcntl.h	2015-12-04 14:19:27.857378484 +0300
+++ new/usr/src/uts/common/sys/fcntl.h	2015-12-04 14:19:27.866115185 +0300
@@ -181,6 +181,9 @@
 #endif	/* _STRICT_SYMBOLS */
 #endif /* _LP64 || _FILE_OFFSET_BITS == 32 */
 
+#define	F_ASSOCI_PID	292929
+#define	F_DASSOC_PID	303030
+
 #if 	defined(_LARGEFILE64_SOURCE)
 
 #if !defined(_LP64) || defined(_KERNEL)
--- old/usr/src/uts/common/sys/file.h	2015-12-04 14:19:28.061373363 +0300
+++ new/usr/src/uts/common/sys/file.h	2015-12-04 14:19:28.069580133 +0300
@@ -204,7 +204,7 @@
 #ifndef	_BOOT
 extern void closeall(uf_info_t *);
 #endif
-extern void flist_fork(uf_info_t *, uf_info_t *);
+extern void flist_fork(proc_t *, proc_t *);
 extern int closef(file_t *);
 extern int closeandsetf(int, file_t *);
 extern int ufalloc_file(int, file_t *);
--- /dev/null	2015-12-04 14:19:28.000000000 +0300
+++ new/usr/src/uts/common/sys/pidnode.h	2015-12-04 14:19:28.265882855 +0300
@@ -0,0 +1,55 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Mohamed A. Khalfella <khalfella@gmail.com>
+ */
+
+#ifndef _SYS_PIDNODE_H
+#define	_SYS_PIDNODE_H
+
+#include <sys/avl.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define	CONN_PID_INFO_MGC	0x5A7A0B1D
+
+#define	CONN_PID_INFO_NON	0
+#define	CONN_PID_INFO_SOC	1
+#define	CONN_PID_INFO_XTI	2
+
+typedef struct conn_pid_info_s {
+	uint16_t	cpi_contents;	/* CONN_PID_INFO_* */
+	uint32_t	cpi_magic;	/* CONN_PID_INFO_MGC */
+	uint32_t	cpi_pids_cnt;	/* # of elements in cpi_pids */
+	uint32_t	cpi_tot_size;	/* total size of hdr + pids */
+	pid_t		cpi_pids[1];	/* varialbe length array of pids */
+} conn_pid_info_t;
+
+#if defined(_KERNEL)
+
+typedef struct pid_node_s {
+	avl_node_t	pn_ref_link;
+	uint32_t	pn_count;
+	pid_t		pn_pid;
+} pid_node_t;
+
+extern int pid_node_comparator(const void *, const void *);
+
+#endif /* defined(_KERNEL) */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _SYS_PIDNODE_H */
--- old/usr/src/uts/common/sys/socket_proto.h	2015-12-04 14:19:28.361744841 +0300
+++ new/usr/src/uts/common/sys/socket_proto.h	2015-12-04 14:19:28.368797034 +0300
@@ -30,6 +30,7 @@
 #endif
 
 #include <sys/socket.h>
+#include <sys/pidnode.h>
 
 /*
  * Generation count
@@ -200,6 +201,7 @@
 	void	(*su_zcopy_notify)(sock_upper_handle_t);
 	void	(*su_set_error)(sock_upper_handle_t, int);
 	void	(*su_closed)(sock_upper_handle_t);
+	mblk_t *(*su_get_sock_pid_mblk)(sock_upper_handle_t);
 };
 
 #define	SOCK_UC_VERSION		sizeof (sock_upcalls_t)
--- old/usr/src/uts/common/sys/socketvar.h	2015-12-04 14:19:28.564592878 +0300
+++ new/usr/src/uts/common/sys/socketvar.h	2015-12-04 14:19:28.571747725 +0300
@@ -46,6 +46,7 @@
 #include <sys/stream.h>
 #include <sys/t_lock.h>
 #include <sys/cred.h>
+#include <sys/pidnode.h>
 #include <sys/vnode.h>
 #include <sys/file.h>
 #include <sys/param.h>
@@ -244,6 +245,10 @@
 	struct sof_instance	*so_filter_top;		/* top of stack */
 	struct sof_instance	*so_filter_bottom;	/* bottom of stack */
 	clock_t			so_filter_defertime;	/* time when deferred */
+
+	/* pid tree */
+	avl_tree_t		so_pid_tree;
+	kmutex_t		so_pid_tree_lock;
 };
 
 #define	SO_HAVE_DATA(so)						\
@@ -951,8 +956,14 @@
 /*
  * Internal structure for obtaining sonode information from the socklist.
  * These types match those corresponding in the sonode structure.
- * This is not a published interface, and may change at any time.
+ * This is not a published interface, and may change at any time. It is
+ * used for passing information back up to the kstat consumers. By converting
+ * kernel addresses to strings, we should be able to pass information from
+ * the kernel to userland regardless of n-bit kernel we are using.
  */
+
+#define	ADRSTRLEN (2 * sizeof (uint64_t) + 1)
+
 struct sockinfo {
 	uint_t		si_size;		/* real length of this struct */
 	short		si_family;
@@ -970,6 +981,11 @@
 	char		si_faddr_sun_path[MAXPATHLEN + 1];
 	boolean_t	si_faddr_noxlate;
 	zoneid_t	si_szoneid;
+	char		si_son_straddr[ADRSTRLEN];
+	char		si_lvn_straddr[ADRSTRLEN];
+	char		si_fvn_straddr[ADRSTRLEN];
+	uint_t		si_pn_cnt;
+	pid_t		si_pids[1];
 };
 
 /*
--- old/usr/src/uts/common/sys/strsubr.h	2015-12-04 14:19:28.827452859 +0300
+++ new/usr/src/uts/common/sys/strsubr.h	2015-12-04 14:19:28.838010065 +0300
@@ -44,6 +44,7 @@
 #include <sys/proc.h>
 #include <sys/netstack.h>
 #include <sys/modhash.h>
+#include <sys/pidnode.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -241,6 +242,11 @@
 	uint_t		sd_copyflag;	/* copy-related flags */
 	zoneid_t	sd_anchorzone;	/* Allow removal from same zone only */
 	struct msgb	*sd_cmdblk;	/* reply from _I_CMD */
+	/*
+	 * pids associated with this stream head.
+	 */
+	avl_tree_t	sd_pid_tree;
+	kmutex_t	sd_pid_tree_lock;
 } stdata_t;
 
 /*
@@ -1140,6 +1146,9 @@
 extern int strwaitbuf(size_t, int);
 extern int strwaitq(stdata_t *, int, ssize_t, int, clock_t, int *);
 extern struct stdata *shalloc(queue_t *);
+extern void sh_insert_pid(struct stdata *, pid_t);
+extern void sh_remove_pid(struct stdata *, pid_t);
+extern mblk_t *sh_get_pid_mblk(struct stdata *);
 extern void shfree(struct stdata *s);
 extern queue_t *allocq(void);
 extern void freeq(queue_t *);
--- old/usr/src/uts/common/syscall/fcntl.c	2015-12-04 14:19:29.077408282 +0300
+++ new/usr/src/uts/common/syscall/fcntl.c	2015-12-04 14:19:29.084317600 +0300
@@ -179,6 +179,13 @@
 				f_setfd(retval, FD_CLOEXEC);
 			}
 		}
+
+		if (error == 0 && fp->f_vnode != NULL) {
+			(void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
+			    (intptr_t)p->p_pidp->pid_id, FKIOCTL, kcred,
+			    NULL, NULL);
+		}
+
 		goto done;
 
 	case F_DUP2FD_CLOEXEC:
@@ -215,6 +222,14 @@
 			fp->f_count++;
 			mutex_exit(&fp->f_tlock);
 			releasef(fdes);
+
+			/* assume we have forked successfully */
+			if (fp->f_vnode != NULL) {
+				(void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
+				    (intptr_t)p->p_pidp->pid_id, FKIOCTL,
+				    kcred, NULL, NULL);
+			}
+
 			if ((error = closeandsetf(iarg, fp)) == 0) {
 				if (cmd == F_DUP2FD_CLOEXEC) {
 					f_setfd(iarg, FD_CLOEXEC);
@@ -225,6 +240,13 @@
 				if (fp->f_count > 1) {
 					fp->f_count--;
 					mutex_exit(&fp->f_tlock);
+					if (fp->f_vnode != NULL) {
+						(void) VOP_IOCTL(fp->f_vnode,
+						    F_DASSOC_PID,
+						    (intptr_t)p->p_pidp->pid_id,
+						    FKIOCTL, kcred, NULL, NULL);
+					}
+
 				} else {
 					mutex_exit(&fp->f_tlock);
 					(void) closef(fp);
