--- /dev/null	2012-07-09 14:38:13.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_input.c	2012-07-09 14:38:13.271776939 +0000
@@ -0,0 +1,544 @@
+/*
+ * 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/ip.h>
+
+#include <sys/cmn_err.h>
+
+#include "dccp_impl.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 *);
+
+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;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_input");
+
+	/* Assume IP provides aligned packets */
+	ASSERT(OK_32PTR(mp->b_rptr));
+	ASSERT((MBLKL(mp) >= sizeof (ipha_t)));
+
+	/* Verify IP version. */
+	if (!(ira->ira_flags & IRAF_IS_IPV4)) {
+		dccp_icmp_error_ipv6(dccp, mp, ira);
+		return;
+	}
+
+}
+
+static void
+dccp_icmp_error_ipv6(dccp_t *dccp, mblk_t *mp, ip_recv_attr_t *ira)
+{
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_icmp_error_ipv6");
+}
+
+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);
+
+	if (type != DCCP_PKT_REQUEST) {
+		cmn_err(CE_NOTE, "not request pkt");
+
+		/* XXX do something with a reset packet sent? */
+		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);
+
+	CONN_INC_REF(lconnp);
+	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_REQUEST_RCVD;
+	DTRACE_DCCP6(state__change, void, NULL, ip_xmit_attr_t *,
+	    econnp->conn_ixa, void, NULL, dccp_t *, eager, void, NULL,
+	    int32_t, DCCPS_LISTEN);
+
+/*
+	mp1 = dccp_xmit_mp(eager, eager->dccp_xmit_head, 0,
+	    NULL, NULL, 0, B_FALSE, NULL, B_FALSE);
+*/
+	mp1 = dccp_generate_packet(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 SYN-ACK. 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_TCP5(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_TCP_SEND_SYNACK); /* XXX */
+	}
+
+	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);
+}
+
+/*
+ * 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;
+	uchar_t		*iphdr;
+	uchar_t		*rptr;
+	sock_upcalls_t	*sockupcalls;
+	uint_t		ip_hdr_len;
+
+	cmn_err(CE_NOTE, "dccp_input.c: dccp_input_data");
+
+	iphdr = mp->b_rptr;
+	rptr = mp->b_rptr;
+	ASSERT(OK_32PTR(rptr));
+
+	ip_hdr_len = ira->ira_ip_hdr_length;
+
+	ASSERT(DB_TYPE(mp) == M_DATA);
+	ASSERT(mp->b_next == NULL);
+
+	dccpha = (dccpha_t *)&rptr[ip_hdr_len];
+}
+
