--- old/usr/src/uts/common/inet/ip/ipclassifier.c	2012-07-09 14:38:17.990471773 +0000
+++ new/usr/src/uts/common/inet/ip/ipclassifier.c	2012-07-09 14:38:18.103735562 +0000
@@ -223,6 +223,7 @@
  *		IPCL_UDPCONN	indicates a UDP conn_t.
  *		IPCL_RAWIPCONN	indicates a RAWIP/ICMP conn_t.
  *		IPCL_RTSCONN	indicates a RTS conn_t.
+ *		IPCL_DCCPCONN	indicates a DCCP conn_t.
  *		IPCL_IPCCONN	indicates all other connections.
  *
  * void ipcl_conn_destroy(connp)
@@ -257,6 +258,7 @@
 #include <inet/ip_ndp.h>
 #include <inet/ip_impl.h>
 #include <inet/udp_impl.h>
+#include <inet/dccp/dccp_impl.h>
 #include <inet/sctp_ip.h>
 #include <inet/sctp/sctp_impl.h>
 #include <inet/rawip_impl.h>
@@ -280,8 +282,9 @@
 uint_t ipcl_conn_hash_memfactor = 8192;
 uint_t ipcl_conn_hash_maxsize = 82500;
 
-/* bind/udp fanout table size */
+/* bind/dccp/udp fanout table size */
 uint_t ipcl_bind_fanout_size = 512;
+uint_t ipcl_dccp_fanout_size = 512;
 uint_t ipcl_udp_fanout_size = 16384;
 
 /* Raw socket fanout size.  Must be a power of 2. */
@@ -319,6 +322,7 @@
 struct kmem_cache  *udp_conn_cache;
 struct kmem_cache  *rawip_conn_cache;
 struct kmem_cache  *rts_conn_cache;
+struct kmem_cache  *dccp_conn_cache;
 
 extern void	tcp_timermp_free(tcp_t *);
 extern mblk_t	*tcp_timermp_alloc(int);
@@ -338,6 +342,9 @@
 static int	rts_conn_constructor(void *, void *, int);
 static void	rts_conn_destructor(void *, void *);
 
+static int	dccp_conn_constructor(void *, void *, int);
+static void	dccp_conn_destructor(void *, void *);
+
 /*
  * Global (for all stack instances) init routine
  */
@@ -368,6 +375,12 @@
 	    sizeof (itc_t) + sizeof (rts_t), CACHE_ALIGN_SIZE,
 	    rts_conn_constructor, rts_conn_destructor,
 	    NULL, NULL, NULL, 0);
+
+	/* XXX:DCCP reclaim */
+	dccp_conn_cache = kmem_cache_create("dccp_conn_cache",
+	    sizeof (itc_t) + sizeof (dccp_t), CACHE_ALIGN_SIZE,
+	    dccp_conn_constructor, dccp_conn_destructor,
+	    NULL, NULL, NULL, 0);
 }
 
 /*
@@ -410,6 +423,7 @@
 
 	/* Take values from /etc/system */
 	ipst->ips_ipcl_bind_fanout_size = ipcl_bind_fanout_size;
+	ipst->ips_ipcl_dccp_fanout_size = ipcl_dccp_fanout_size;
 	ipst->ips_ipcl_udp_fanout_size = ipcl_udp_fanout_size;
 	ipst->ips_ipcl_raw_fanout_size = ipcl_raw_fanout_size;
 	ipst->ips_ipcl_iptun_fanout_size = ipcl_iptun_fanout_size;
@@ -477,6 +491,13 @@
 		mutex_init(&ipst->ips_ipcl_globalhash_fanout[i].connf_lock,
 		    NULL, MUTEX_DEFAULT, NULL);
 	}
+
+	ipst->ips_ipcl_dccp_fanout = kmem_zalloc(
+	    ipst->ips_ipcl_dccp_fanout_size * sizeof (connf_t), KM_SLEEP);
+	for (i = 0; i < ipst->ips_ipcl_dccp_fanout_size; i++) {
+		mutex_init(&ipst->ips_ipcl_dccp_fanout[i].connf_lock, NULL,
+		    MUTEX_DEFAULT, NULL);
+	}
 }
 
 void
@@ -487,6 +508,7 @@
 	kmem_cache_destroy(udp_conn_cache);
 	kmem_cache_destroy(rawip_conn_cache);
 	kmem_cache_destroy(rts_conn_cache);
+	kmem_cache_destroy(dccp_conn_cache);
 }
 
 /*
@@ -562,6 +584,14 @@
 	    sizeof (connf_t) * CONN_G_HASH_SIZE);
 	ipst->ips_ipcl_globalhash_fanout = NULL;
 
+	for (i = 0; i < ipst->ips_ipcl_dccp_fanout_size; i++) {
+		ASSERT(ipst->ips_ipcl_dccp_fanout[i].connf_head == NULL);
+		mutex_destroy(&ipst->ips_ipcl_dccp_fanout[i].connf_lock);
+	}
+	kmem_free(ipst->ips_ipcl_dccp_fanout, ipst->ips_ipcl_dccp_fanout_size *
+	    sizeof (connf_t));
+	ipst->ips_ipcl_dccp_fanout = NULL;
+
 	ASSERT(ipst->ips_rts_clients->connf_head == NULL);
 	mutex_destroy(&ipst->ips_rts_clients->connf_lock);
 	kmem_free(ipst->ips_rts_clients, sizeof (connf_t));
@@ -610,6 +640,10 @@
 		conn_cache = ip_conn_cache;
 		break;
 
+	case IPCL_DCCPCONN:
+		conn_cache = dccp_conn_cache;
+		break;
+
 	default:
 		connp = NULL;
 		ASSERT(0);
@@ -720,6 +754,23 @@
 		return;
 	}
 
+	if (connp->conn_flags & IPCL_DCCPCONN) {
+		dccp_t	*dccp = connp->conn_dccp;
+
+		cmn_err(CE_NOTE, "ipclassifier: conn_flags DCCP cache_free");
+
+		/* XXX:DCCP */
+		/* Crash bug here: udp_conn_cache and dccp_conn_cache */
+/*
+		ipcl_conn_cleanup(connp);
+		connp->conn_flags = IPCL_DCCPCONN;
+		bzero(dccp, sizeof (dccp_t));
+		dccp->dccp_connp = connp;
+		kmem_cache_free(dccp_conn_cache, connp);
+		return;
+*/
+	}
+
 	ipcl_conn_cleanup(connp);
 	if (ns != NULL) {
 		connp->conn_netstack = NULL;
@@ -1236,8 +1287,22 @@
 	case IPPROTO_SCTP:
 		ret = ipcl_sctp_hash_insert(connp, lport);
 		break;
+
+	case IPPROTO_DCCP:
+		cmn_err(CE_NOTE, "ipcl_bind_insert_v4");
+		ASSERT(connp->conn_zoneid != ALL_ZONES);
+		connfp = &ipst->ips_ipcl_dccp_fanout[
+		    IPCL_DCCP_HASH(lport, ipst)];
+		if (connp->conn_laddr_v4 != INADDR_ANY) {
+			IPCL_HASH_INSERT_BOUND(connfp, connp);
+		} else {
+			IPCL_HASH_INSERT_WILDCARD(connfp, connp);
+		}
+		/* XXX:DCCP */
+		break;
 	}
 
+
 	return (ret);
 }
 
@@ -1309,6 +1374,10 @@
 	case IPPROTO_SCTP:
 		ret = ipcl_sctp_hash_insert(connp, lport);
 		break;
+
+	case IPPROTO_DCCP:
+		/* XXX:DCCP */
+		break;
 	}
 
 	return (ret);
@@ -1393,6 +1462,18 @@
 		ret = ipcl_sctp_hash_insert(connp, lport);
 		break;
 
+	case IPPROTO_DCCP:
+		cmn_err(CE_NOTE, "ipclassifier.c: ipcl_conn_insert_v4");
+
+		connfp = &ipst->ips_ipcl_conn_fanout[
+		    IPCL_CONN_HASH(connp->conn_faddr_v4,
+		    connp->conn_ports, ipst)];
+		mutex_enter(&connfp->connf_lock);
+
+		IPCL_HASH_INSERT_CONNECTED_LOCKED(connfp, connp);
+		mutex_exit(&connfp->connf_lock);
+		break;
+
 	default:
 		/*
 		 * Check for conflicts among MAC exempt bindings.  For
@@ -1488,6 +1569,10 @@
 		ret = ipcl_sctp_hash_insert(connp, lport);
 		break;
 
+	case IPPROTO_DCCP:
+		/* XXX:DCCP */
+		break;
+
 	default:
 		if (is_system_labeled() &&
 		    check_exempt_conflict_v6(connp, ipst))
@@ -1655,6 +1740,31 @@
 
 		break;
 
+	case IPPROTO_DCCP:
+		fport = up[0];
+		lport = up[1];
+		connfp = &ipst->ips_ipcl_dccp_fanout[IPCL_DCCP_HASH(
+		    lport, ipst)];
+		mutex_enter(&connfp->connf_lock);
+		for (connp = connfp->connf_head; connp != NULL;
+		    connp = connp->conn_next) {
+			cmn_err(CE_NOTE, "connfp found");
+			/* XXX:DCCP */
+			if (IPCL_UDP_MATCH(connp, lport, ipha->ipha_dst,
+			    fport, ipha->ipha_src)) {
+				break;
+			}
+		}
+
+		if (connp != NULL) {
+			CONN_INC_REF(connp);
+			mutex_exit(&connfp->connf_lock);
+			return (connp);
+		}
+
+		mutex_exit(&connfp->connf_lock);
+		break;
+
 	case IPPROTO_ENCAP:
 	case IPPROTO_IPV6:
 		return (ipcl_iptun_classify_v4(&ipha->ipha_src,
@@ -2175,6 +2285,61 @@
 	}
 }
 
+/* ARGSUSED */
+static int
+dccp_conn_constructor(void *buf, void *cdrarg, int kmflags)
+{
+	itc_t	*itc = (itc_t *)buf;
+	conn_t	*connp = &itc->itc_conn;
+	dccp_t	*dccp = (dccp_t *)&itc[1];
+
+	bzero(connp, sizeof (conn_t));
+	bzero(dccp, sizeof (dccp_t));
+
+	mutex_init(&connp->conn_lock, NULL, MUTEX_DEFAULT, NULL);
+	cv_init(&connp->conn_cv, NULL, CV_DEFAULT, NULL);
+	rw_init(&connp->conn_ilg_lock, NULL, RW_DEFAULT, NULL);
+
+	connp->conn_dccp = dccp;
+	connp->conn_flags = IPCL_DCCPCONN;
+	connp->conn_proto = IPPROTO_DCCP;
+	dccp->dccp_connp = connp;
+	connp->conn_ixa = kmem_zalloc(sizeof (ip_xmit_attr_t), kmflags);
+	if (connp->conn_ixa == NULL) {
+		return (NULL);
+	}
+	connp->conn_ixa->ixa_refcnt = 1;
+	connp->conn_ixa->ixa_protocol = connp->conn_proto;
+	connp->conn_ixa->ixa_xmit_hint = CONN_TO_XMIT_HINT(connp);
+
+	return (0);
+}
+
+/* ARGSUSED */
+static void
+dccp_conn_destructor(void *buf, void *cdrarg)
+{
+	itc_t	*itc = (itc_t *)buf;
+	conn_t	*connp = &itc->itc_conn;
+	dccp_t	*dccp = (dccp_t *)&itc[1];
+
+	ASSERT(connp->conn_flags & IPCL_DCCPCONN);
+	ASSERT(dccp->dccp_connp == connp);
+	ASSERT(connp->conn_dccp == dccp);
+
+	mutex_destroy(&connp->conn_lock);
+	cv_destroy(&connp->conn_cv);
+	rw_destroy(&connp->conn_ilg_lock);
+
+	if (connp->conn_ixa != NULL) {
+		ASSERT(connp->conn_ixa->ixa_refcnt == 1);
+		ASSERT(connp->conn_ixa->ixa_ire == NULL);
+		ASSERT(connp->conn_ixa->ixa_nce == NULL);
+
+		ixa_refrele(connp->conn_ixa);
+	}
+}
+
 /*
  * Called as part of ipcl_conn_destroy to assert and clear any pointers
  * in the conn_t.
