--- /dev/null	2012-08-08 12:42:10.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_input.c	2012-08-08 12:42:10.101298720 +0000
@@ -0,0 +1,927 @@
+/*
+ * 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.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2012 David Hoeppner.  All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/strsubr.h>
+#include <sys/stropts.h>
+#include <sys/strlog.h>
+#define	_SUN_TPI_VERSION 2
+#include <sys/tihdr.h>
+#include <sys/suntpi.h>
+#include <sys/xti_inet.h>
+#include <sys/squeue_impl.h>
+#include <sys/squeue.h>
+#include <sys/tsol/tnet.h>
+
+#include <inet/common.h>
+#include <inet/dccp_impl.h>
+#include <inet/ip.h>
+
+#include <sys/cmn_err.h>
+
+static mblk_t	*dccp_conn_create_v4(conn_t *, conn_t *, mblk_t *,
+		    ip_recv_attr_t *);
+static mblk_t	*dccp_conn_create_v6(conn_t *, conn_t *, mblk_t *,
+		    ip_recv_attr_t *);
+static void	dccp_input_listener(void *, mblk_t *, void *, ip_recv_attr_t *);
+static void	dccp_icmp_error_ipv6(dccp_t *, mblk_t *, ip_recv_attr_t *);
+static int	dccp_check_input(conn_t *, mblk_t *, ip_recv_attr_t *);
+
+void
+dccp_icmp_input(void *arg1, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
+{
+	conn_t	*connp = (conn_t *)arg1;
+	dccp_t	*dccp = connp->conn_dccp;
+	ipha_t	*ipha;
+	icmph_t	*icmph;
+	sin_t	sin;
+	sin6_t	sin6;
+	int	iph_hdr_length;
+	int 	error;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_input");
+
+	ipha = (ipha_t *)mp->b_rptr;
+
+	/* Assume IP provides aligned packets */
+	ASSERT(OK_32PTR(mp->b_rptr));
+	ASSERT((MBLKL(mp) >= sizeof (ipha_t)));
+
+	if (dccp->dccp_state == DCCPS_CLOSED) {
+		freemsg(mp);
+		return;
+	}
+
+	/*
+	 * Verify IP version. Anything other than IPv4 or IPv6 packet is sent
+	 * upstream. ICMPv6 is handled in dccp_icmp_error_ipv6.
+	 */
+	if (IPH_HDR_VERSION(ipha) != IPV4_VERSION) {
+		ASSERT(IPH_HDR_VERSION(ipha) == IPV6_VERSION);
+		dccp_icmp_error_ipv6(dccp, mp, ira);
+		return;
+	}
+	ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
+
+	ASSERT(IPH_HDR_LENGTH(ipha) == ira->ira_ip_hdr_length);
+	/* Skip past the outer IP and ICMP headers */
+	iph_hdr_length = ira->ira_ip_hdr_length;
+	icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length];
+
+	switch (icmph->icmph_type) {
+	case ICMP_DEST_UNREACHABLE:
+		switch (icmph->icmph_code) {
+		case ICMP_FRAGMENTATION_NEEDED:
+		case ICMP_PORT_UNREACHABLE:
+		case ICMP_PROTOCOL_UNREACHABLE:
+		case ICMP_HOST_UNREACHABLE:
+		case ICMP_NET_UNREACHABLE:
+			break;
+		default:
+			break;
+		}
+		break;
+	case ICMP_SOURCE_QUENCH:
+		break;
+	}
+
+	freemsg(mp);
+}
+
+/*
+ * Handler for ICMPv6 error messages.
+ */
+static void
+dccp_icmp_error_ipv6(dccp_t *dccp, mblk_t *mp, ip_recv_attr_t *ira)
+{
+	ip6_t		*ip6h;
+	icmp6_t		*icmp6;
+	uint16_t	iph_hdr_length = ira->ira_ip_hdr_length;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_error_ipv6");
+
+	ASSERT((MBLKL(mp) >= sizeof (ip6_t)));
+
+	icmp6 = (icmp6_t *)&mp->b_rptr[iph_hdr_length];
+	ip6h = (ip6_t *)&icmp6[1];
+
+}
+
+void
+dccp_rsrv(queue_t *q)
+{
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_rsrv");
+}
+
+/*
+ * Handle a REQUEST on an AF_INET6 socket; can be either IPv4 or IPv6.
+ */
+static mblk_t *
+dccp_conn_create_v6(conn_t *lconnp, conn_t *connp, mblk_t *mp,
+    ip_recv_attr_t *ira)
+{
+	dccp_t		*ldccp = lconnp->conn_dccp;
+	dccp_t		*dccp = connp->conn_dccp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	ipha_t		*ipha;
+	ip6_t		*ip6h;
+	mblk_t		*tpi_mp;
+	sin6_t		sin6;
+	uint_t		ifindex = ira->ira_ruifindex;
+
+	if (ira->ira_flags & IRAF_IS_IPV4) {
+		ipha = (ipha_t *)mp->b_rptr;
+
+		connp->conn_ipversion = IPV4_VERSION;
+		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &connp->conn_laddr_v6);
+		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &connp->conn_faddr_v6);
+		connp->conn_saddr_v6 = connp->conn_laddr_v6;
+
+		sin6 = sin6_null;
+		sin6.sin6_addr = connp->conn_faddr_v6;
+		sin6.sin6_port = connp->conn_fport;
+		sin6.sin6_family = AF_INET6;
+		sin6.__sin6_src_id = ip_srcid_find_addr(&connp->conn_laddr_v6,
+		    IPCL_ZONEID(lconnp), dccps->dccps_netstack);
+
+		if (connp->conn_recv_ancillary.crb_recvdstaddr) {
+			sin6_t	sin6d;
+
+			sin6d = sin6_null;
+			sin6d.sin6_addr = connp->conn_laddr_v6;
+			sin6d.sin6_port = connp->conn_lport;
+			sin6d.sin6_family = AF_INET;
+			tpi_mp = mi_tpi_extconn_ind(NULL,
+			    (char *)&sin6d, sizeof (sin6_t),
+			    (char *)&dccp,
+			    (t_scalar_t)sizeof (intptr_t),
+			    (char *)&sin6d, sizeof (sin6_t),
+			    (t_scalar_t)ldccp->dccp_conn_req_seqnum);
+		} else {
+			tpi_mp = mi_tpi_conn_ind(NULL,
+			    (char *)&sin6, sizeof (sin6_t),
+			    (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
+			    (t_scalar_t)ldccp->dccp_conn_req_seqnum);
+		}
+	} else {
+		ip6h = (ip6_t *)mp->b_rptr;
+
+		connp->conn_ipversion = IPV6_VERSION;
+		connp->conn_laddr_v6 = ip6h->ip6_dst;
+		connp->conn_faddr_v6 = ip6h->ip6_src;
+		connp->conn_saddr_v6 = connp->conn_laddr_v6;
+
+		sin6 = sin6_null;
+		sin6.sin6_addr = connp->conn_faddr_v6;
+		sin6.sin6_port = connp->conn_fport;
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK;
+		sin6.__sin6_src_id = ip_srcid_find_addr(&connp->conn_laddr_v6,
+		    IPCL_ZONEID(lconnp), dccps->dccps_netstack);
+
+		if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_src)) {
+			/* Pass up the scope_id of remote addr */
+			sin6.sin6_scope_id = ifindex;
+		} else {
+			sin6.sin6_scope_id = 0;
+		}
+		if (connp->conn_recv_ancillary.crb_recvdstaddr) {
+			sin6_t	sin6d;
+
+			sin6d = sin6_null;
+			sin6.sin6_addr = connp->conn_laddr_v6;
+			sin6d.sin6_port = connp->conn_lport;
+			sin6d.sin6_family = AF_INET6;
+			if (IN6_IS_ADDR_LINKSCOPE(&connp->conn_laddr_v6))
+				sin6d.sin6_scope_id = ifindex;
+
+			tpi_mp = mi_tpi_extconn_ind(NULL,
+			    (char *)&sin6d, sizeof (sin6_t),
+			    (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
+			    (char *)&sin6d, sizeof (sin6_t),
+			    (t_scalar_t)ldccp->dccp_conn_req_seqnum);
+		} else {
+			tpi_mp = mi_tpi_conn_ind(NULL,
+			    (char *)&sin6, sizeof (sin6_t),
+			    (char *)&dccp, (t_scalar_t)sizeof (intptr_t),
+			    (t_scalar_t)ldccp->dccp_conn_req_seqnum);
+		}
+	}
+
+	/* XXX mss */
+	return (tpi_mp);
+}
+
+/*
+ * Handle a REQUEST on an AF_INET socket.
+ */
+static mblk_t *
+dccp_conn_create_v4(conn_t *lconnp, conn_t *connp, mblk_t *mp,
+    ip_recv_attr_t *ira)
+{
+	dccp_t		*ldccp = lconnp->conn_dccp;
+	dccp_t		*dccp = connp->conn_dccp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	ipha_t		*ipha;
+	mblk_t		*tpi_mp;
+	sin_t		sin;
+
+	ASSERT(ira->ira_flags & IRAF_IS_IPV4);
+	ipha = (ipha_t *)mp->b_rptr;
+
+	connp->conn_ipversion = IPV4_VERSION;
+	IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &connp->conn_laddr_v6);
+	IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &connp->conn_faddr_v6);
+	connp->conn_saddr_v6 = connp->conn_laddr_v6;
+
+	sin = sin_null;
+	sin.sin_addr.s_addr = connp->conn_faddr_v4;
+	sin.sin_port = connp->conn_fport;
+	sin.sin_family = AF_INET;
+
+	if (lconnp->conn_recv_ancillary.crb_recvdstaddr) {
+		cmn_err(CE_NOTE, "ancillary");
+
+		sin_t   sind;
+
+		sind = sin_null;
+		sind.sin_addr.s_addr = connp->conn_laddr_v4;
+		sind.sin_port = connp->conn_lport;
+		sind.sin_family = AF_INET;
+
+		tpi_mp = mi_tpi_extconn_ind(NULL,
+		    (char *)&sind, sizeof (sin_t), (char *)&dccp,
+		    (t_scalar_t)sizeof (intptr_t), (char *)&sind,
+		    sizeof (sin_t), (t_scalar_t)ldccp->dccp_conn_req_seqnum);
+
+	} else {
+		tpi_mp = mi_tpi_conn_ind(NULL,
+		(char *)&sin, sizeof (sin_t),
+		(char *)&dccp, (t_scalar_t)sizeof (intptr_t),
+		(t_scalar_t)ldccp->dccp_conn_req_seqnum);
+	}
+
+	/* XXX mss */
+
+	return (tpi_mp);
+}
+
+static void
+dccp_input_listener(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
+{
+	conn_t		*lconnp = (conn_t *)arg;
+	conn_t		*econnp;
+	dccp_t		*listener = lconnp->conn_dccp;
+	dccp_t		*eager;
+	dccp_stack_t	*dccps = listener->dccp_dccps;
+	ip_stack_t	*ipst = dccps->dccps_netstack->netstack_ip;
+	dccpha_t	*dccpha;
+	squeue_t	*new_sqp;
+	mblk_t		*tpi_mp;
+	mblk_t		*mp1;
+	uint_t		ifindex = ira->ira_ruifindex;
+	uint_t		ip_hdr_len;
+	uint_t		type;
+	int		error;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener");
+
+	ip_hdr_len = ira->ira_ip_hdr_length;
+	dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
+	type = (uint_t)dccpha->dha_type;
+
+	DTRACE_DCCP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, lconnp->conn_ixa,
+	    __dtrace_dccp_void_ip_t *, mp->b_rptr, dccp_t *, listener,
+	    __dtrace_dccp_dccph_t *, dccpha);
+
+	dccp_check_input(lconnp, mp, ira);
+
+	if (type != DCCP_PKT_REQUEST) {
+		cmn_err(CE_NOTE, "--- not request pkt");
+		if (type != DCCP_PKT_RESET) {
+			/* XXX send Reset(No Connection) */
+		}
+
+		freemsg(mp);
+		return;
+	}
+
+	/* XXX memory pressure */
+
+	/* XXX request defense */
+
+	/* XXX number of connections per listener */
+
+	ASSERT(ira->ira_sqp != NULL);
+	new_sqp = ira->ira_sqp;
+
+	econnp = (conn_t *)dccp_get_conn(arg2, dccps);
+	if (econnp == NULL) {
+		cmn_err(CE_NOTE, "econnp not found (eager)");
+		goto error2;
+	}
+
+	ASSERT(econnp->conn_netstack == lconnp->conn_netstack);
+	econnp->conn_sqp = new_sqp;
+	econnp->conn_initial_sqp = new_sqp;
+	econnp->conn_ixa->ixa_sqp = new_sqp;
+
+	econnp->conn_fport = dccpha->dha_lport;
+	econnp->conn_lport = dccpha->dha_fport;
+
+	error = conn_inherit_parent(lconnp, econnp);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "conn_inherit_parent failed");
+		goto error3;
+	}
+
+	/* We already know the laddr of the new connection is ours */
+	econnp->conn_ixa->ixa_src_generation = ipst->ips_src_generation;
+
+	ASSERT(OK_32PTR(mp->b_rptr));
+	ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION ||
+	    IPH_HDR_VERSION(mp->b_rptr) == IPV6_VERSION);
+
+	if (lconnp->conn_family == AF_INET) {
+		ASSERT(IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION);
+		tpi_mp = dccp_conn_create_v4(lconnp, econnp, mp, ira);
+	} else {
+		tpi_mp = dccp_conn_create_v6(lconnp, econnp, mp, ira);
+	}
+
+	if (tpi_mp == NULL) {
+		cmn_err(CE_NOTE, "tpi_mo == NULL");
+		goto error3;
+	}
+
+	eager = econnp->conn_dccp;
+	SOCK_CONNID_INIT(eager->dccp_connid);
+
+	dccp_init_values(eager, listener);
+
+	ASSERT((econnp->conn_ixa->ixa_flags &
+	    (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
+	    IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO)) ==
+	    (IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
+	    IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO));
+
+	if (!(ira->ira_flags & IRAF_IS_IPV4) && econnp->conn_bound_if == 0) {
+		if (IN6_IS_ADDR_LINKSCOPE(&econnp->conn_faddr_v6) ||
+		    IN6_IS_ADDR_LINKSCOPE(&econnp->conn_laddr_v6)) {
+			econnp->conn_incoming_ifindex = ifindex;
+			econnp->conn_ixa->ixa_flags |= IXAF_SCOPEID_SET;
+			econnp->conn_ixa->ixa_scopeid = ifindex;
+		}
+	}
+
+	if (ira->ira_cred != NULL) {
+		mblk_setcred(tpi_mp, ira->ira_cred, ira->ira_cpid);
+	}
+
+	if (IPCL_IS_NONSTR(lconnp)) {
+		econnp->conn_flags |= IPCL_NONSTR;
+	}
+
+	/* XXX dccps is right? */
+	dccp_bind_hash_insert(&dccps->dccps_bind_fanout[
+	    DCCP_BIND_HASH(econnp->conn_lport, dccps->dccps_bind_fanout_size)],
+	    eager, 0);
+
+	/* XXX CLUSTER */
+
+	SOCK_CONNID_BUMP(eager->dccp_connid);
+
+	error = dccp_set_destination(eager);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "dccp_set_destination failed.");
+		dccp_bind_hash_remove(eager);
+		goto error3;
+	}
+
+	/* Process all DCCP options */
+	dccp_process_options(eager, dccpha);
+
+	/* Eager lock */
+	CONN_INC_REF(lconnp);
+
+	/* Set tcp_listener before adding it to tcp_conn_fanout */
+	eager->dccp_listener = listener;
+	eager->dccp_saved_listener = listener;
+
+	eager->dccp_conn_req_seqnum = listener->dccp_conn_req_seqnum;
+	if (++listener->dccp_conn_req_seqnum == -1) {
+		/*
+		 * -1 is "special" and defined in TPI as something
+		 * that should never be used in T_CONN_IND
+		 */
+		++listener->dccp_conn_req_seqnum;
+	}
+
+	/* XXX SYN DEFENSE */
+
+	eager->dccp_state = DCCPS_RESPOND;
+	DTRACE_DCCP6(state__change, void, NULL, ip_xmit_attr_t *,
+	    econnp->conn_ixa, void, NULL, dccp_t *, eager, void, NULL,
+	    int32_t, DCCPS_LISTEN);
+
+	/* ISS was set in set_destionation */
+	eager->dccp_gar = eager->dccp_iss;
+
+	mp1 = dccp_generate_response(econnp, mp);
+	if (mp1 == NULL) {
+		cmn_err(CE_NOTE, "dccp_generate_packet failed");
+		/*
+                 * Increment the ref count as we are going to
+                 * enqueueing an mp in squeue
+                 */
+		CONN_INC_REF(econnp);
+		goto error;
+	}
+
+	CONN_INC_REF(econnp);
+
+	error = ipcl_conn_insert(econnp);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "ipcl_conn_insert(econnp) failed");
+		goto error;
+	}
+
+	ASSERT(econnp->conn_ixa->ixa_notify_cookie == econnp->conn_dccp);
+	freemsg(mp);
+
+        /*
+         * Send the RESPONSE. Use the right squeue so that conn_ixa is
+         * only used by one thread at a time.
+         */
+	if (econnp->conn_sqp == lconnp->conn_sqp) {
+		DTRACE_DCCP5(send, mblk_t *, NULL, ip_xmit_attr_t *,
+		    econnp->conn_ixa, __dtrace_dccp_void_ip_t *, mp1->b_rptr,
+		    dccp_t *, eager, __dtrace_dccp_dccph_t *,
+		    &mp1->b_rptr[econnp->conn_ixa->ixa_ip_hdr_length]);
+		(void) conn_ip_output(mp1, econnp->conn_ixa);
+		CONN_DEC_REF(econnp);
+	} else {
+		SQUEUE_ENTER_ONE(econnp->conn_sqp, mp1, dccp_send_synack,
+		    econnp, NULL, SQ_PROCESS, SQTAG_DCCP_SEND_RESPONSE);
+	}
+
+	return;
+error:
+	freemsg(mp1);
+error2:
+	CONN_DEC_REF(econnp);
+error3:
+	freemsg(mp);
+}
+
+void
+dccp_input_listener_unbound(void *arg, mblk_t *mp, void *arg2,
+    ip_recv_attr_t *ira)
+{
+	conn_t		*connp = (conn_t *)arg;
+	squeue_t	*sqp = (squeue_t *)arg2;
+	squeue_t	*new_sqp;
+	uint32_t	conn_flags;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_input_listener_unbound");
+
+	ASSERT(ira->ira_sqp != NULL);
+	new_sqp = ira->ira_sqp;
+
+	if (connp->conn_fanout == NULL) {
+		goto done;
+	}
+
+	/*
+	 * Bind to correct squeue.
+	 */
+	if (!(connp->conn_flags & IPCL_FULLY_BOUND)) {
+		cmn_err(CE_NOTE, "not fully bound");
+
+		mutex_enter(&connp->conn_fanout->connf_lock);
+		mutex_enter(&connp->conn_lock);
+
+		if (connp->conn_ref != 4 ||
+		    connp->conn_dccp->dccp_state != DCCPS_LISTEN) {
+			mutex_exit(&connp->conn_lock);
+			mutex_exit(&connp->conn_fanout->connf_lock);
+			goto done;
+		}
+
+		if (connp->conn_sqp != new_sqp) {
+			while (connp->conn_sqp != new_sqp) {
+				(void) casptr(&connp->conn_sqp, sqp, new_sqp);
+			}
+			connp->conn_ixa->ixa_sqp = new_sqp;
+		}
+
+		do {
+			conn_flags = connp->conn_flags;
+			conn_flags |= IPCL_FULLY_BOUND;
+			(void) cas32(&connp->conn_flags, connp->conn_flags,
+			    conn_flags);
+		} while (!(connp->conn_flags & IPCL_FULLY_BOUND));
+
+		mutex_exit(&connp->conn_lock);
+		mutex_exit(&connp->conn_fanout->connf_lock);
+
+		connp->conn_recv = dccp_input_listener;
+	}
+
+done:
+	if (connp->conn_sqp != sqp) {
+		CONN_INC_REF(connp);
+		SQUEUE_ENTER_ONE(connp->conn_sqp, mp, connp->conn_recv, connp,
+		    ira, SQ_FILL, SQTAG_DCCP_CONN_REQ_UNBOUND);
+	} else {
+		dccp_input_listener(connp, mp, sqp, ira);
+	}
+}
+
+boolean_t
+dccp_verifyicmp(conn_t *connp, void *arg2, icmph_t *icmph, icmp6_t *icmp6,
+    ip_recv_attr_t *ira)
+{
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_verifyicmp");
+
+	return (B_TRUE);
+}
+
+/*
+ * Basic sanity checks on all input packets.
+ */
+static int
+dccp_check_input(conn_t *connp, mblk_t *mp, ip_recv_attr_t *ira)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccpha_t	*dccpha;
+	uint32_t	size;
+	uint32_t	pkt_size;
+	uint_t		ip_hdr_len = ira->ira_ip_hdr_length;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_check_input");
+
+	size = msgdsize(mp) - (ip_hdr_len);
+	dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
+	pkt_size = dccpha->dha_offset * 4;
+
+	/* Is packet shorter then 12 bytes? */
+	if (size < DCCP_MIN_HEADER_LENGTH) {
+		return (0);
+	}
+
+	/* Data offset is greater then the packet itself */
+	if (pkt_size > size) {
+		return (0);
+	}
+
+	/* Check if known packet type */
+	if (dccpha->dha_type > DCCP_PKT_SYNCACK) {
+		return (0);
+	}
+
+	/*
+	 * Check data offset for this packet type and
+	 * Data, Ack, or DataAck and P.X == 0
+	 */
+	if (dccpha->dha_x == 0) {
+		switch (dccpha->dha_type) {
+		case DCCP_PKT_DATA:
+			if (size < 12 || pkt_size < 12)
+				return (0);
+			break;
+		case DCCP_PKT_ACK:
+		case DCCP_PKT_DATAACK:
+			if (size < 16 || pkt_size < 16)
+				return (0);
+			break;
+		default:
+			return (0);
+		}
+	} else {
+		switch (dccpha->dha_type) {
+		case DCCP_PKT_REQUEST:
+			if (size < 20 || pkt_size < 20)
+				return (0);
+			break;
+		case DCCP_PKT_RESPONSE:
+		case DCCP_PKT_RESET:
+			if (size < 28 || pkt_size < 28)
+				return (0);
+			break;
+		case DCCP_PKT_DATA:
+			if (size < 16 || pkt_size < 16)
+				return (0);
+			break;
+		case DCCP_PKT_ACK:
+		case DCCP_PKT_DATAACK:
+		case DCCP_PKT_CLOSEREQ:
+		case DCCP_PKT_CLOSE:
+		case DCCP_PKT_SYNC:
+		case DCCP_PKT_SYNCACK:
+			if (size < 24 || pkt_size < 24)
+				return (0);
+			break;
+		default:
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+/*
+ * After a request-response-ack all packets end up here.
+ */
+void
+dccp_input_data(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
+{
+	conn_t		*connp = (conn_t *)arg;
+	squeue_t	*sqp = (squeue_t *)arg2;
+	dccp_t		*dccp = connp->conn_dccp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	dccpha_t	*dccpha;
+	dccpha_ack_t	*dccpha_ack;
+	dccpha_ext_t	*dccpha_ext;
+	mblk_t		*mp1;
+	uint64_t	seq_seq;
+	uint64_t	seq_ack;
+	uchar_t		*iphdr;
+	uchar_t		*rptr;
+	sock_upcalls_t	*sockupcalls;
+	ip_pkt_t	ipp;
+	uint_t		ip_hdr_len;
+	uint_t		len;
+	int		seg_len;
+	int		pkt_len;
+	int		hdr_length;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_input_data");
+
+	ASSERT(DB_TYPE(mp) == M_DATA);
+	ASSERT(mp->b_next == NULL);
+
+	iphdr = mp->b_rptr;
+	rptr = mp->b_rptr;
+	ASSERT(OK_32PTR(rptr));
+
+	/* Check basic packet characteristics */
+	if (dccp_check_input(connp, mp, ira) == 0) {
+		cmn_err(CE_NOTE, "reject packet");
+		return;
+	}
+
+	ip_hdr_len = ira->ira_ip_hdr_length;
+	if (connp->conn_recv_ancillary.crb_all != 0) {
+		/*
+		 * Record packet information in the ip_pkt_t
+		 */
+		ipp.ipp_fields = 0;
+		if (ira->ira_flags & IRAF_IS_IPV4) {
+			(void) ip_find_hdr_v4((ipha_t *)rptr, &ipp,
+			    B_FALSE);
+		} else {
+			uint8_t nexthdrp;
+
+			/*
+			 * IPv6 packets can only be received by applications
+			 * that are prepared to receive IPv6 addresses.
+			 * The IP fanout must ensure this.
+			 */
+			ASSERT(connp->conn_family == AF_INET6);
+
+			(void) ip_find_hdr_v6(mp, (ip6_t *)rptr, B_TRUE, &ipp,
+			     &nexthdrp);
+			ASSERT(nexthdrp == IPPROTO_DCCP);
+
+			/* Could have caused a pullup? */
+			iphdr = mp->b_rptr;
+			rptr = mp->b_rptr;
+		}
+	}
+
+	len = ip_hdr_len;
+	dccpha = (dccpha_t *)&rptr[len];
+
+	ASSERT((uintptr_t)(mp->b_wptr - rptr) <= (uintptr_t)INT_MAX);
+	seg_len = (int)(mp->b_wptr - rptr) -
+	    (ip_hdr_len + DCCP_HDR_LENGTH(dccpha));
+	if ((mp1 = mp->b_cont) != NULL && mp1->b_datap->db_type == M_DATA) {
+		do {
+			ASSERT((uintptr_t)(mp1->b_wptr - mp1->b_rptr) <=
+			    (uintptr_t)INT_MAX);
+			seg_len += (int)(mp1->b_wptr - mp1->b_rptr);
+		} while ((mp1 = mp1->b_cont) != NULL &&
+		    mp1->b_datap->db_type == M_DATA);
+	}
+
+	DTRACE_DCCP5(receive, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa,
+	    __dtrace_dccp_void_ip_t *, iphdr, dccp_t *, dccp,
+	    __dtrace_dccp_dccph_t *, dccpha);
+
+	BUMP_LOCAL(dccp->dccp_ibsegs);
+	DTRACE_PROBE2(dccp__trace__recv, mblk_t *, mp, dccp_t *, dccp);
+
+	sockupcalls = connp->conn_upcalls;
+
+	len += sizeof (dccpha_t);
+	dccpha_ext = (dccpha_ext_t *)&rptr[len];
+
+	/* XXX length checks */
+	if (dccpha->dha_x == 1) {
+		seq_seq = ntohs(dccpha->dha_seq);
+		seq_seq = seq_seq << 32;
+		seq_seq |= ntohl(dccpha_ext->dha_ext_seq);
+	} else {
+		/* XXX */
+	}
+
+	dccp->dccp_gsr = seq_seq;
+
+	switch (dccp->dccp_state) {
+	case DCCPS_REQUEST:
+		cmn_err(CE_NOTE, "DCCPS_REQUEST");
+		break;
+	case DCCPS_RESPOND:
+		cmn_err(CE_NOTE, "DCCPS_RESPOND");
+		break;
+	case DCCPS_PARTOPEN:
+		cmn_err(CE_NOTE, "DCCPS_PARTOPEN");
+		break;
+	case DCCPS_LISTEN:
+		cmn_err(CE_NOTE, "DCCPS_LISTEN");
+		break;
+	case DCCPS_BOUND:
+		cmn_err(CE_NOTE, "DCCPS_BOUND");
+		break;
+	case DCCPS_OPEN:
+		cmn_err(CE_NOTE, "DCCPS_OPEN");
+		break;
+	default:
+		cmn_err(CE_NOTE, "Unknow state");
+		break;
+	}
+
+	if (dccp->dccp_state == DCCPS_RESPOND) {
+		dccp->dccp_state = DCCPS_OPEN;
+		//dccp->dccp_osr = DCCP_SEQNO_GET(mp);
+
+		if (dccp->dccp_active_open) {
+			cmn_err(CE_NOTE, "dccp_active_open");
+			if (!dccp_conn_con(dccp, iphdr, mp, NULL, ira)) {
+				cmn_err(CE_NOTE, "dccp_conn_con failed");
+				freemsg(mp);
+				dccp->dccp_state = DCCPS_RESPOND;
+				return;
+			}
+
+			DTRACE_DCCP5(connect__established, mblk_t *, NULL,
+			    ip_xmit_attr_t *, connp->conn_ixa, void_ip_t *,
+			    iphdr, dccp_t *, dccp, dccph_t *, dccpha);
+		} else if (IPCL_IS_NONSTR(connp)) {
+			/*
+			 * Passive open socket
+			 */
+			cmn_err(CE_NOTE, "nonstr");
+
+			CONN_INC_REF(connp);
+
+			if (!dccp_newconn_notify(dccp, ira)) {
+				cmn_err(CE_NOTE, "dccp_newconn_notify failed");
+				dccp->dccp_state = DCCPS_RESPOND;
+				freemsg(mp);
+
+				CONN_DEC_REF(connp);
+				return;
+			}
+
+			/*
+			 * dccp_newconn_notify() changes conn_upcalls.
+			 */
+			if (connp->conn_upcalls != NULL) {
+				sockupcalls = connp->conn_upcalls;
+			}
+
+			DTRACE_DCCP5(accept__established, mlbk_t *, NULL,
+			    ip_xmit_attr_t *, connp->conn_ixa, void_ip_t *,
+			    iphdr, dccp_t *, dccp, dccph_t *, dccpha);
+		} else {
+			cmn_err(CE_NOTE, "str stream");
+			dccp_t	*listener = dccp->dccp_listener;
+
+			ASSERT(mp != NULL);
+			CONN_INC_REF(connp);
+		}
+	}
+
+	switch (dccpha->dha_type) {
+	case DCCP_PKT_REQUEST:
+		cmn_err(CE_NOTE, "DCCP_REQUEST");
+		break;
+	case DCCP_PKT_RESPONSE:
+		cmn_err(CE_NOTE, "DCCP_RESPONSE");
+		break;
+	case DCCP_PKT_DATA:
+		cmn_err(CE_NOTE, "DCCP_DATA");
+		break;
+	case DCCP_PKT_ACK:
+		cmn_err(CE_NOTE, "DCCP_PKT_ACK");
+		break;
+	case DCCP_PKT_DATAACK:
+		cmn_err(CE_NOTE, "DCCP_DATAACK");
+		break;
+	case DCCP_PKT_CLOSEREQ:
+		cmn_err(CE_NOTE, "DCCP_CLOSEREQ");
+		break;
+	case DCCP_PKT_CLOSE:
+		cmn_err(CE_NOTE, "DCCP_CLOSE");
+		break;
+	case DCCP_PKT_RESET:
+		cmn_err(CE_NOTE, "DCCP_RESET");
+		break;
+	case DCCP_PKT_SYNC:
+		cmn_err(CE_NOTE, "DCCP_SYNC");
+		break;
+	case DCCP_PKT_SYNCACK:
+		cmn_err(CE_NOTE, "DCCP_SYNCACK");
+		break;
+	default:
+		break;
+	}
+
+	switch (dccpha->dha_type) {
+	case DCCP_PKT_ACK:
+		dccp->dccp_state = DCCPS_OPEN;
+		return;
+	case DCCP_PKT_DATAACK:
+		dccp->dccp_state = DCCPS_OPEN;
+		break;
+	case DCCP_PKT_CLOSE: {
+		mblk_t	*reset_mp;
+
+		reset_mp = dccp_generate_reset(connp);
+		dccp_send_data(dccp, reset_mp);
+		dccp->dccp_state = DCCPS_CLOSED;
+		return;
+	}
+	default:
+		break;
+	}
+
+	hdr_length = ira->ira_ip_hdr_length;
+	hdr_length += DCCP_HDR_LENGTH(dccpha);
+	pkt_len = ira->ira_pktlen;
+
+	mp->b_wptr = rptr + pkt_len;
+	mp->b_rptr = (uchar_t *)&mp->b_rptr[hdr_length];
+	pkt_len -= hdr_length;
+
+	if (IPCL_IS_NONSTR(connp)) {
+		/*
+		 * Non-STREAMS socket.
+		 */
+		boolean_t	push;
+		int		error;
+
+		if ((*sockupcalls->su_recv)(connp->conn_upper_handle,
+		    mp, pkt_len, 0, &error, NULL) <= 0) {
+			cmn_err(CE_NOTE, "su_recv failed");
+			ASSERT(error != EOPNOTSUPP);
+		}
+	} else if (dccp->dccp_listener != NULL) {
+		// dccp_recv_enqueue(dccp, mp, seq_len, ira->ira_cred);
+	} else {
+		/*
+		 * Active-STREAMS socket.
+		 */
+	}
+}
