--- /dev/null	2012-07-09 14:38:14.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_stats.c	2012-07-09 14:38:14.080168149 +0000
@@ -0,0 +1,262 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2012 David Hoeppner.  All rights reserved.
+ */
+
+/*
+ * Functions related to MIB-II and kstat.
+ */
+
+#include <sys/types.h>
+#include <sys/tihdr.h>
+#include <sys/policy.h>
+#include <sys/tsol/tnet.h>
+
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/kstatcom.h>
+#include <inet/snmpcom.h>
+
+#include <sys/cmn_err.h>
+
+#include "dccp_impl.h"
+
+static int	dccp_snmp_state(dccp_t *);
+static int	dccp_kstat_update(kstat_t *, int);
+
+/*
+ * Translate DCCP state to MIB2 state.
+ */
+static int
+dccp_snmp_state(dccp_t *dccp)
+{
+	if (dccp == NULL) {
+		return (0);
+	}
+
+	switch(dccp->dccp_state) {
+	case DCCPS_CLOSED:
+		return (MIB2_DCCP_closed);
+	default:
+		return (0);
+	}
+}
+
+/*
+ * Get the MIB-II stats.
+ */
+mblk_t *
+dccp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req)
+{
+	conn_t		*connp = Q_TO_CONN(q);
+	connf_t		*connfp;
+	ip_stack_t	*ipst;
+	dccp_stack_t	*dccps;
+	struct opthdr	*optp;
+	mblk_t		*mp2ctl;
+	mblk_t		*mpdata;
+	mblk_t		*mp_conn_ctl = NULL;
+	mblk_t		*mp_conn_tail;
+	mblk_t		*mp_attr_ctl = NULL;
+	mblk_t		*mp_attr_tail;
+	mblk_t		*mp6_conn_ctl = NULL;
+	mblk_t		*mp6_conn_tail;
+	mblk_t		*mp6_attr_ctl = NULL;
+	mblk_t		*mp6_attr_tail;
+	size_t		dccp_mib_size;
+	size_t		dce_size;
+	size_t		dce6_size;
+	zoneid_t	zoneid;
+	int		i;
+	mib2_dccp_t		dccp_mib;
+	mib2_dccpConnEntry_t	dce;
+	mib2_dccp6ConnEntry_t	dce6;
+
+	/*
+	 * Make a copy of the original message.
+	 */
+	mp2ctl = copymsg(mpctl);
+
+	cmn_err(CE_NOTE, "dccp_stats.c: dccp_snmp_get");
+
+	if (mpctl == NULL ||
+	    (mpdata = mpctl->b_cont) == NULL ||
+	    (mp_conn_ctl = copymsg(mpctl)) == NULL ||
+	    (mp_attr_ctl = copymsg(mpctl)) == NULL) {
+		freemsg(mp_conn_ctl);
+		freemsg(mp_attr_ctl);
+		freemsg(mpctl);
+		freemsg(mp2ctl);
+		return (NULL);
+	}
+
+	ipst = connp->conn_netstack->netstack_ip;
+	dccps = connp->conn_netstack->netstack_dccp;
+
+	if (legacy_req) {
+		dccp_mib_size = LEGACY_MIB_SIZE(&dccp_mib, mib2_dccp_t);
+		dce_size = LEGACY_MIB_SIZE(&dce, mib2_dccpConnEntry_t);
+		dce6_size = LEGACY_MIB_SIZE(&dce6, mib2_dccp6ConnEntry_t);
+	} else {
+		dccp_mib_size = sizeof (mib2_dccp_t);
+		dce_size = sizeof (mib2_dccpConnEntry_t);
+		dce6_size = sizeof (mib2_dccp6ConnEntry_t);
+	}
+
+	bzero(&dccp_mib, sizeof (dccp_mib));
+	zoneid = Q_TO_CONN(q)->conn_zoneid;
+	mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
+
+	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
+		ipst = dccps->dccps_netstack->netstack_ip;
+
+		connfp = &ipst->ips_ipcl_globalhash_fanout[i];
+		connp = NULL;
+
+		while ((connp = ipcl_get_next_conn(connfp, connp,
+		    IPCL_DCCPCONN)) != NULL) {
+			dccp_t	*dccp;
+
+			if (connp->conn_zoneid != zoneid) {
+				continue;
+			}
+
+			dccp = connp->conn_dccp;
+
+			dce.dccpConnState = dccp_snmp_state(dccp);
+
+			if (connp->conn_ipversion == IPV4_VERSION ||
+			    (dccp->dccp_state <= DCCPS_LISTEN)) {
+
+				if (connp->conn_ipversion == IPV6_VERSION) {
+					dce.dccpConnRemAddress = INADDR_ANY;
+					dce.dccpConnLocalAddress = INADDR_ANY;
+				} else {
+					dce.dccpConnRemAddress =
+					    connp->conn_faddr_v4;
+					dce.dccpConnLocalAddress =
+					    connp->conn_laddr_v4;
+				}
+
+			dce.dccpConnLocalPort = ntohs(connp->conn_lport);
+			dce.dccpConnRemPort = ntohs(connp->conn_fport);
+/*
+			dce.dccpConnCreationProcess = (connp->conn_cpid < 0) ?
+			    MIB2_UNKNOWN_PROCESS : connp->conn_cpid;
+			dce.dccpConnCreationTime = connp->conn_open_time;
+*/
+			(void) snmp_append_data2(mp_conn_ctl->b_cont,
+			    &mp_conn_tail, (char *)&dce, dce_size);
+
+			}
+		}
+	}
+
+	SET_MIB(dccp_mib.dccpConnTableSize, dce_size);
+	SET_MIB(dccp_mib.dccp6ConnTableSize, dce6_size);
+
+	optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_DCCP;
+	optp->name = 0;
+	(void) snmp_append_data(mpdata, (char *)&dccp_mib, dccp_mib_size);
+	optp->len = msgdsize(mpdata);
+	qreply(q, mpctl);
+
+	optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_DCCP;
+	optp->name = MIB2_DCCP_CONN;
+	optp->len = msgdsize(mp_conn_ctl->b_cont);
+	qreply(q, mp_conn_ctl);
+
+	optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
+	    sizeof (struct T_optmgmt_ack)];
+	optp->level = MIB2_DCCP;
+	optp->name = EXPER_XPORT_MLP;
+	optp->len = msgdsize(mp_attr_ctl->b_cont);
+	if (optp->len == 0) {
+		freemsg(mp_attr_ctl);
+	} else {
+		qreply(q, mp_attr_ctl);
+	}
+
+	return (mp2ctl);
+}
+
+/*
+ * DCCP kernel statistics.
+ */
+void *
+dccp_kstat_init(netstackid_t stackid)
+{
+	kstat_t	*ksp;
+
+	dccp_named_kstat_t template = {
+		{ "activeOpens",	KSTAT_DATA_UINT32, 0 },
+		{ "passiveOpens",	KSTAT_DATA_UINT32, 0 },
+		{ "inSegs",		KSTAT_DATA_UINT64, 0 },
+		{ "outSegs",		KSTAT_DATA_UINT64, 0 },
+	};
+
+	ksp = kstat_create_netstack(DCCP_MOD_NAME, 0, DCCP_MOD_NAME, "mib2",
+	    KSTAT_TYPE_NAMED, NUM_OF_FIELDS(dccp_named_kstat_t), 0, stackid);
+	if (ksp == NULL) {
+		return (NULL);
+	}
+
+	bcopy(&template, ksp->ks_data, sizeof (template));
+	ksp->ks_update = dccp_kstat_update;
+	ksp->ks_private = (void *)(uintptr_t)stackid;
+
+	kstat_install(ksp);
+
+	return (ksp);
+}
+
+/*
+ * Destroy DCCP kernel statistics.
+ */
+void
+dccp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
+{
+
+	if (ksp != NULL) {
+		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
+		kstat_delete_netstack(ksp, stackid);
+	}
+}
+
+/*
+ * Update DCCP kernel statistics.
+ */
+static int
+dccp_kstat_update(kstat_t *ksp, int rw)
+{
+
+	if (rw == KSTAT_WRITE) {
+		return (EACCES);
+	}
+
+	return (0);
+}
