--- /dev/null	2012-06-13 12:04:29.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp.c	2012-06-13 12:04:29.030621901 +0000
@@ -0,0 +1,876 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file implements the Data Congestion Control Protocol (DCCP).
+ */
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/strlog.h>
+#include <sys/strsun.h>
+#define	_SUN_TPI_VERSION 2
+#include <sys/tihdr.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sockio.h>
+#include <sys/vtrace.h>
+#include <sys/sdt.h>
+#include <sys/debug.h>
+#include <sys/isa_defs.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/tnet.h>
+#include <inet/kstatcom.h>
+#include <inet/snmpcom.h>
+
+#include <sys/cmn_err.h>
+
+#include "dccp_impl.h"
+#include "dccp_stack.h"
+
+/* Setable in /etc/system */
+uint_t dccp_bind_fanout_size = DCCP_BIND_FANOUT_SIZE;
+
+static void	dccp_notify(void *, ip_xmit_attr_t *, ixa_notify_type_t,
+		    ixa_notify_arg_t);
+
+/* Functions to register netstack */
+static void	*dccp_stack_init(netstackid_t, netstack_t *);
+static void	dccp_stack_fini(netstackid_t, void *);
+
+static int	dccp_openv4(queue_t *, dev_t *, int, int, cred_t *);
+static int	dccp_openv6(queue_t *, dev_t *, int, int, cred_t *);
+
+/* Write service routine */
+static void	dccp_wsrv(queue_t *);
+
+/* Connection related functions */
+static int	dccp_connect_ipv4(dccp_t *, ipaddr_t *, in_port_t, uint_t);
+static int	dccp_connect_ipv6(dccp_t *, in6_addr_t *, in_port_t, uint32_t,
+    uint_t, uint32_t);
+
+struct module_info dccp_rinfo = {
+	DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, DCCP_RECV_HIWATER,
+	DCCP_RECV_LOWATER
+};
+
+static struct module_info dccp_winfo = {
+	DCCP_MOD_ID, DCCP_MOD_NAME, 0, INFPSZ, 127, 16
+};
+
+/*
+ * Queue information structure with DCCP entry points.
+ */
+struct qinit dccp_rinitv4 = {
+	NULL, (pfi_t)dccp_rsrv, dccp_openv4, dccp_tpi_close, NULL, &dccp_rinfo
+};
+
+struct qinit dccp_rinitv6 = {
+	NULL, (pfi_t)dccp_rsrv, dccp_openv6, dccp_tpi_close, NULL, &dccp_rinfo
+};
+
+struct qinit dccp_winit = {
+	(pfi_t)dccp_wput, (pfi_t)dccp_wsrv, NULL, NULL, NULL, &dccp_winfo
+};
+
+/* AF_INET /dev/dccp */
+struct streamtab dccpinfov4 = {
+	&dccp_rinitv4, &dccp_winit
+};
+
+/* AF_INET6 /dev/dccp6 */
+struct streamtab dccpinfov6 = {
+	&dccp_rinitv6, &dccp_winit
+};
+
+/*
+ * Tunables.
+ */
+extern mod_prop_info_t dccp_propinfo_tbl[];
+extern int dccp_propinfo_count;
+
+/*
+ * Register DCCP netstack.
+ */
+void
+dccp_ddi_g_init(void)
+{
+	netstack_register(NS_DCCP, dccp_stack_init, NULL, dccp_stack_fini);
+}
+
+#define	INET_NAME	"ip"
+
+/*
+ * Initialize the DCCP stack instance.
+ */
+static void *
+dccp_stack_init(netstackid_t stackid, netstack_t *ns)
+{
+	dccp_stack_t	*dccps;
+	major_t		major;
+	size_t		arrsz;
+	int		error;
+	int		i;
+
+	dccps = kmem_zalloc(sizeof (*dccps), KM_SLEEP);
+	if (dccps == NULL) {
+		return (NULL);
+	}
+	dccps->dccps_netstack = ns;
+
+	/* Ports */
+	mutex_init(&dccps->dccps_epriv_port_lock, NULL, MUTEX_DEFAULT, NULL);
+	dccps->dccps_num_epriv_ports = DCCP_NUM_EPRIV_PORTS;
+	dccps->dccps_epriv_ports[0] = ULP_DEF_EPRIV_PORT1;
+	dccps->dccps_epriv_ports[1] = ULP_DEF_EPRIV_PORT2;
+	dccps->dccps_min_anonpriv_port = 512;
+
+	dccps->dccps_bind_fanout_size = dccp_bind_fanout_size;
+
+	/* Bind fanout */
+	dccps->dccps_bind_fanout = kmem_zalloc(dccps->dccps_bind_fanout_size *
+	    sizeof (dccp_df_t), KM_SLEEP);
+	for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
+		mutex_init(&dccps->dccps_bind_fanout[i].df_lock, NULL,
+		    MUTEX_DEFAULT, NULL);
+	}
+
+	/* Tunable properties */
+	arrsz = dccp_propinfo_count * sizeof (mod_prop_info_t);
+	dccps->dccps_propinfo_tbl = kmem_alloc(arrsz, KM_SLEEP);
+	if (dccps->dccps_propinfo_tbl == NULL) {
+		kmem_free(dccps, sizeof (*dccps));
+		return (NULL);
+	}
+	bcopy(dccp_propinfo_tbl, dccps->dccps_propinfo_tbl, arrsz);
+
+	/* Allocate per netstack cpu stats */
+	mutex_enter(&cpu_lock);
+	dccps->dccps_sc_cnt = MAX(ncpus, boot_ncpus);
+	mutex_exit(&cpu_lock);
+
+	dccps->dccps_sc = kmem_zalloc(max_ncpus * sizeof (dccp_stats_cpu_t *),
+	    KM_SLEEP);
+	for (i = 0; i < dccps->dccps_sc_cnt; i++) {
+		dccps->dccps_sc[i] = kmem_zalloc(sizeof (dccp_stats_cpu_t),
+		    KM_SLEEP);
+	}
+
+	/* Driver major number */
+	major = mod_name_to_major(INET_NAME);
+	error = ldi_ident_from_major(major, &dccps->dccps_ldi_ident);
+	ASSERT(error == 0);
+
+	return (dccps);
+}
+
+/*
+ * Destroy the DCCP stack instance.
+ */
+void
+dccp_ddi_g_destroy(void)
+{
+	cmn_err(CE_NOTE, "dccp.c: dccp_ddi_g_destroy\n");
+
+	netstack_unregister(NS_DCCP);
+}
+
+static void
+dccp_stack_fini(netstackid_t stackid, void *arg)
+{
+	dccp_stack_t	*dccps = (dccp_stack_t *)arg;
+	int		i;
+
+	/* Cpu stats */
+	for (i = 0; i < dccps->dccps_sc_cnt; i++) {
+		kmem_free(dccps->dccps_sc[i], sizeof (dccp_stats_cpu_t));
+	}
+	kmem_free(dccps->dccps_sc, max_ncpus * sizeof (dccp_stats_cpu_t *));
+
+	/* Tunable properties */
+	kmem_free(dccps->dccps_propinfo_tbl,
+	    dccp_propinfo_count * sizeof (mod_prop_info_t));
+	dccps->dccps_propinfo_tbl = NULL;
+
+	/* Bind fanout */
+	for (i = 0; i < dccps->dccps_bind_fanout_size; i++) {
+		ASSERT(dccps->dccps_bind_fanout[i].df_dccp == NULL);
+		mutex_destroy(&dccps->dccps_bind_fanout[i].df_lock);
+	}
+	kmem_free(dccps->dccps_bind_fanout, dccps->dccps_bind_fanout_size *
+	    sizeof (dccp_df_t));
+	dccps->dccps_bind_fanout = NULL;
+
+	kmem_free(dccps, sizeof (*dccps));
+}
+
+/* /dev/dccp */
+static int
+dccp_openv4(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
+{
+	cmn_err(CE_NOTE, "dccp.c: dccp_openv4\n");
+
+	return (ENOTSUP);
+}
+
+/* /dev/dccp6 */
+static int
+dccp_openv6(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
+{
+	cmn_err(CE_NOTE, "dccp.c: dccp_openv6\n");
+
+	return (ENOTSUP);
+}
+
+/*
+ * IXA notify
+ */
+static void
+dccp_notify(void *arg, ip_xmit_attr_t *ixa, ixa_notify_type_t ntype,
+    ixa_notify_arg_t narg)
+{
+	cmn_err(CE_NOTE, "dccp.c: dccp_notify");
+}
+
+/*
+ * Build the template headers.
+ */
+int
+dccp_build_hdrs(dccp_t *dccp)
+{
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	conn_t		*connp = dccp->dccp_connp;
+	dccpha_t	*dccpha;
+	uint32_t	cksum;
+	char		buf[DCCP_MAX_HDR_LENGTH];
+	uint_t		buflen;
+	uint_t		ulplen = 12;
+	uint_t		extralen = 0;
+	int		error;
+
+	cmn_err(CE_NOTE, "dccp.c: dccp_build_hdrs");
+
+	buflen = connp->conn_ht_ulp_len;
+	if (buflen != 0) {
+		cmn_err(CE_NOTE, "buflen != 0");
+		bcopy(connp->conn_ht_ulp, buf, buflen);
+		extralen -= buflen - ulplen;
+		ulplen = buflen;
+	}
+
+	mutex_enter(&connp->conn_lock);
+	error = conn_build_hdr_template(connp, ulplen, extralen,
+	    &connp->conn_laddr_v6, &connp->conn_faddr_v6, connp->conn_flowinfo);
+	mutex_exit(&connp->conn_lock);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "conn_build_hdr_template failed");
+		return (error);
+	}
+
+	dccpha = (dccpha_t *)connp->conn_ht_ulp;
+	dccp->dccp_dccpha = dccpha;
+
+	if (buflen != 0) {
+		bcopy(buf, connp->conn_ht_ulp, buflen);
+	} else {
+		dccpha->dha_sum = 0;
+		dccpha->dha_lport = connp->conn_lport;
+		dccpha->dha_fport = connp->conn_fport;
+	}
+
+	cksum = sizeof (dccpha_t) + connp->conn_sum;
+	cksum = (cksum >> 16) + (cksum & 0xFFFF);
+	dccpha->dha_sum = htons(cksum);
+	dccpha->dha_offset = 7;
+	dccpha->dha_x = 1;
+
+	return (0);
+}
+
+/*
+ * DCCP write service routine.
+ */
+static void
+dccp_wsrv(queue_t *q)
+{
+	/* XXX:DCCP */
+}
+
+/*
+ * Common create function for streams and sockets.
+ */
+conn_t *
+dccp_create_common(cred_t *credp, boolean_t isv6, boolean_t issocket,
+    int *errorp)
+{
+	conn_t		*connp;
+	dccp_t		*dccp;
+	dccp_stack_t	*dccps;
+	netstack_t	*ns;
+	squeue_t	*sqp;
+	zoneid_t	zoneid;
+
+	cmn_err(CE_NOTE, "dccp.c: dccp_create_common\n");
+
+	ASSERT(errorp != NULL);
+
+	*errorp = secpolicy_basic_net_access(credp);
+	if (*errorp != 0) {
+		return (NULL);
+	}
+
+	/*
+	 * Find the right netstack
+	 */
+	ns = netstack_find_by_cred(credp);
+	ASSERT(ns != NULL);
+	dccps = ns->netstack_dccp;
+	ASSERT(dccps != NULL);
+
+	/*
+	 * XXX
+	 */
+	if (ns->netstack_stackid != GLOBAL_NETSTACKID) {
+		zoneid = GLOBAL_ZONEID;
+	} else {
+		zoneid = crgetzoneid(credp);
+	}
+
+	sqp = IP_SQUEUE_GET((uint_t)gethrtime());
+	connp = (conn_t *)dccp_get_conn(sqp, dccps);
+	netstack_rele(dccps->dccps_netstack);
+	if (connp == NULL) {
+		*errorp = ENOSR;
+		return (NULL);
+	}
+	ASSERT(connp->conn_ixa->ixa_protocol == connp->conn_proto);
+
+	connp->conn_sqp = sqp;
+	connp->conn_initial_sqp = connp->conn_sqp;
+	connp->conn_ixa->ixa_sqp = connp->conn_sqp;
+	dccp = connp->conn_dccp;
+
+	/* Setting flags for ip output */
+	connp->conn_ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE |
+	    IXAF_VERIFY_PMTU | IXAF_VERIFY_LSO;
+
+	ASSERT(connp->conn_proto == IPPROTO_DCCP);
+	ASSERT(connp->conn_dccp == dccp);
+	ASSERT(dccp->dccp_connp == connp);
+
+	if (isv6) {
+		connp->conn_ixa->ixa_src_preferences = IPV6_PREFER_SRC_DEFAULT;
+		connp->conn_ipversion = IPV6_VERSION;
+		connp->conn_family = AF_INET6;
+		/* XXX mms, ttl */
+	} else {
+		connp->conn_ipversion = IPV4_VERSION;
+		connp->conn_family = AF_INET;
+		/* XXX mms, ttl */
+	}
+	connp->conn_xmit_ipp.ipp_unicast_hops = connp->conn_default_ttl;
+
+	crhold(credp);
+	connp->conn_cred = credp;
+	connp->conn_cpid = curproc->p_pid;
+	connp->conn_open_time = ddi_get_lbolt64();
+
+	ASSERT(!(connp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
+	connp->conn_ixa->ixa_cred = credp;
+	connp->conn_ixa->ixa_cpid = connp->conn_cpid;
+
+	connp->conn_zoneid = zoneid;
+	connp->conn_zone_is_global = (crgetzoneid(credp) == GLOBAL_ZONEID);
+	connp->conn_ixa->ixa_zoneid = zoneid;
+	connp->conn_mlp_type = mlptSingle;
+
+
+	dccp->dccp_dccps = dccps;
+	dccp->dccp_state = DCCPS_CLOSED;
+
+	ASSERT(connp->conn_netstack == dccps->dccps_netstack);
+	ASSERT(dccp->dccp_dccps == dccps);
+
+	/* XXX rcvbuf, sndbuf etc */
+
+	SOCK_CONNID_INIT(dccp->dccp_connid);
+	dccp_init_values(dccp, NULL);
+
+	return (connp);
+}
+
+/*
+ * Common close function for streams and sockets.
+ */
+void
+dccp_close_common(conn_t *connp)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	boolean_t	conn_ioctl_cleanup_reqd = B_FALSE;
+
+	ASSERT(connp->conn_ref >= 2);
+
+	mutex_enter(&connp->conn_lock);
+	connp->conn_state_flags |= CONN_CLOSING;
+	if (connp->conn_oper_pending_ill != NULL) {
+		conn_ioctl_cleanup_reqd = B_TRUE;
+	}
+
+	CONN_INC_REF_LOCKED(connp);
+	mutex_exit(&connp->conn_lock);
+
+	//ipcl_conn_destroy(connp);
+}
+
+/*
+ * Common bind function.
+ */
+int
+dccp_do_bind(conn_t *connp, struct sockaddr *sa, socklen_t len, cred_t *cr,
+    boolean_t bind_to_req_port_only)
+{
+	dccp_t	*dccp = connp->conn_dccp;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp.c: dccp_do_bind");
+
+	if (dccp->dccp_state >= DCCPS_BOUND) {
+		if (connp->conn_debug) {
+			(void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
+			    "dccp_bind: bad state, %d", dccp->dccp_state);
+		}
+		return (-TOUTSTATE);
+	}
+
+	error = dccp_bind_check(connp, sa, len, cr, bind_to_req_port_only);
+	if (error != 0) {
+		return (error);
+	}
+
+	ASSERT(dccp->dccp_state == DCCPS_LISTEN);
+	/* XXX dccp_conn_req_max = 0 */	
+
+	return (0);
+}
+
+/*
+ * Common unbind function.
+ */
+int
+dccp_do_unbind(conn_t *connp)
+{
+	dccp_t	*dccp = connp->conn_dccp;
+
+	cmn_err(CE_NOTE, "dccp.c: dccp_do_unbind");
+
+	switch (dccp->dccp_state) {
+	case DCCPS_BOUND:
+	case DCCPS_LISTEN:
+		break;
+	default:
+		return (-TOUTSTATE);
+	}
+
+	/* XXX:DCCP */
+
+	return (0);
+}
+
+/*
+ * Common listen function.
+ */
+int
+dccp_do_listen(conn_t *connp, struct sockaddr *sa, socklen_t len,
+    int backlog, cred_t *cr, boolean_t bind_to_req_port_only)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	int32_t		oldstate;
+	int		error;
+
+	cmn_err(CE_NOTE, "dccp.c: dccp_do_listen");
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	if (dccp->dccp_state >= DCCPS_BOUND) {
+
+		if ((dccp->dccp_state == DCCPS_BOUND ||
+		    dccp->dccp_state == DCCPS_LISTEN) && backlog > 0) {
+			goto do_listen;
+		}
+		cmn_err(CE_NOTE, "DCCPS_BOUND, bad state");
+
+		if (connp->conn_debug) {
+			(void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
+			    "dccp_listen: bad state, %d", dccp->dccp_state);
+		}
+		return (-TOUTSTATE);
+	} else {
+		if (sa == NULL) {
+			sin6_t	addr;
+			sin6_t	*sin6;
+			sin_t	*sin;
+
+			ASSERT(IPCL_IS_NONSTR(connp));
+
+			if (connp->conn_family == AF_INET) {
+				len = sizeof (sin_t);
+				sin = (sin_t *)&addr;
+				*sin = sin_null;
+				sin->sin_family = AF_INET;
+			} else {
+				ASSERT(connp->conn_family == AF_INET6);
+
+				len = sizeof (sin6_t);
+				sin6 = (sin6_t *)&addr;
+				*sin6 = sin6_null;
+				sin6->sin6_family = AF_INET6;
+			}
+
+			sa = (struct sockaddr *)&addr;
+		}
+
+		error = dccp_bind_check(connp, sa, len, cr,
+		    bind_to_req_port_only);
+		if (error != 0) {
+			cmn_err(CE_NOTE, "dccp_bind_check failed");
+			return (error);
+		}
+		/* Fall through and do the fanout insertion */
+	}
+
+do_listen:
+	ASSERT(dccp->dccp_state == DCCPS_BOUND ||
+	    dccp->dccp_state == DCCPS_LISTEN);
+
+	/* XXX backlog */
+
+	connp->conn_recv = dccp_input_listener_unbound;
+
+	/* Insert into the classifier table */
+	error = ip_laddr_fanout_insert(connp);
+	if (error != 0) {
+		/* Error - undo the bind */
+		oldstate = dccp->dccp_state;
+		dccp->dccp_state = DCCPS_CLOSED;
+
+		connp->conn_bound_addr_v6 = ipv6_all_zeros;
+
+		connp->conn_laddr_v6 = ipv6_all_zeros;
+		connp->conn_saddr_v6 = ipv6_all_zeros;
+		connp->conn_ports = 0;
+
+		if (connp->conn_anon_port) {
+			zone_t	*zone;
+
+			zone = crgetzone(cr);
+			connp->conn_anon_port = B_FALSE;
+			(void) tsol_mlp_anon(zone, connp->conn_mlp_type,
+			    connp->conn_proto, connp->conn_lport, B_FALSE);
+		}
+		connp->conn_mlp_type = mlptSingle;
+
+		/* XXX dccp_bind_hash_remove */
+
+		return (error);
+	} else {
+		/* XXX connection limits */
+	}
+
+	return (error);
+}
+
+/*
+ * Common connect function.
+ */
+int
+dccp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len,
+    cred_t *cr, pid_t pid)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	ip_xmit_attr_t	*ixa = connp->conn_ixa;
+	sin_t		*sin = (sin_t *)sa;
+	sin6_t		*sin6 = (sin6_t *)sa;
+	ipaddr_t	*dstaddrp;
+	in_port_t	dstport;
+	int32_t		oldstate;
+	uint_t		srcid;
+	int		error;
+
+	cmn_err(CE_NOTE, "dccp.c: dccp_do_connect");
+
+	oldstate = dccp->dccp_state;
+
+	switch (len) {
+	case sizeof (sin_t):
+		sin = (sin_t *)sa;
+		if (sin->sin_port == 0) {
+			return (-TBADADDR);
+		}
+		if (connp->conn_ipv6_v6only) {
+			return (EAFNOSUPPORT);
+		}
+		break;
+
+	case sizeof (sin6_t):
+		sin6 = (sin6_t *)sa;
+		if (sin6->sin6_port == 0) {
+			return (-TBADADDR);
+		}
+		break;
+
+	default:
+		return (EINVAL);
+	}
+
+	if (connp->conn_family == AF_INET6 &&
+	    connp->conn_ipversion == IPV6_VERSION &&
+	    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+		if (connp->conn_ipv6_v6only) {
+			return (EADDRNOTAVAIL);
+		}
+
+		connp->conn_ipversion = IPV4_VERSION;
+	}
+
+	switch (dccp->dccp_state) {
+	case DCCPS_LISTEN:
+		if (IPCL_IS_NONSTR(connp)) {
+			return (EOPNOTSUPP);
+		}
+
+	case DCCPS_CLOSED:
+		/* XXX */
+		break;
+
+	default:
+		return (-TOUTSTATE);
+	}
+
+	if (connp->conn_cred != cr) {
+		crhold(cr);
+		crfree(connp->conn_cred);
+		connp->conn_cred = cr;
+	}
+	connp->conn_cpid = pid;
+
+	ASSERT(!(ixa->ixa_free_flags & IXA_FREE_CRED));
+	ixa->ixa_cred = cr;
+	ixa->ixa_cpid = pid;
+
+	if (is_system_labeled()) {
+		ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred);
+	}
+
+	if (connp->conn_family == AF_INET6) {
+		if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+			error = dccp_connect_ipv6(dccp, &sin6->sin6_addr,
+			    sin6->sin6_port, sin6->sin6_flowinfo,
+			    sin6->__sin6_src_id, sin6->sin6_scope_id);
+		} else {
+			/* XXX */
+		}
+	} else {
+		dstaddrp = &sin->sin_addr.s_addr;
+		dstport = sin->sin_port;
+		srcid = 0;
+		error = dccp_connect_ipv4(dccp, dstaddrp, dstport, srcid);
+	}
+
+	if (error != 0) {
+		goto connect_failed;
+	}
+
+	/* XXX cluster */
+
+	//DCCPS_BUMP_MIB(dccps, dccpActiveOpens);
+
+	return (0);
+
+connect_failed:
+	cmn_err(CE_NOTE, "dccp_do_connect failed");
+
+	connp->conn_faddr_v6 = ipv6_all_zeros;
+	connp->conn_fport = 0;
+	dccp->dccp_state = oldstate;
+
+	return (error);
+}
+
+/*
+ * Init values of a connection.
+ */
+void
+dccp_init_values(dccp_t *dccp, dccp_t *parent)
+{
+	conn_t		*connp = dccp->dccp_connp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+
+	connp->conn_mlp_type = mlptSingle;
+}
+
+void *
+dccp_get_conn(void *arg, dccp_stack_t *dccps)
+{
+	dccp_t		*dccp = NULL;
+	conn_t		*connp;
+	squeue_t	*sqp = (squeue_t *)arg;
+	netstack_t	*ns;
+
+	/* XXX timewait */
+
+	connp = ipcl_conn_create(IPCL_DCCPCONN, KM_NOSLEEP,
+	    dccps->dccps_netstack);
+	if (connp == NULL) {
+		return (NULL);
+	}
+
+	dccp = connp->conn_dccp;
+	dccp->dccp_dccps = dccps;
+
+	connp->conn_recv = dccp_input_data;
+	connp->conn_recvicmp = dccp_icmp_input;
+	connp->conn_verifyicmp = dccp_verifyicmp;
+
+	connp->conn_ixa->ixa_notify = dccp_notify;
+	connp->conn_ixa->ixa_notify_cookie = dccp;
+
+	return ((void *)connp);
+}
+
+/*
+ * IPv4 connect.
+ */
+static int
+dccp_connect_ipv4(dccp_t *dccp, ipaddr_t *dstaddrp, in_port_t dstport,
+    uint_t srcid)
+{
+	conn_t		*connp = dccp->dccp_connp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	ipaddr_t	dstaddr = *dstaddrp;
+	uint16_t	lport;
+	int		error;
+
+	cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv4");
+
+	ASSERT(connp->conn_ipversion == IPV4_VERSION);
+
+	if (dstaddr == INADDR_ANY) {
+		dstaddr = htonl(INADDR_LOOPBACK);
+		*dstaddrp = dstaddr;
+	}
+
+	if (srcid != 0 && connp->conn_laddr_v4 == INADDR_ANY) {
+		ip_srcid_find_id(srcid, &connp->conn_laddr_v6,
+		    IPCL_ZONEID(connp), dccps->dccps_netstack);
+		connp->conn_saddr_v6 = connp->conn_laddr_v6;
+	}
+
+	IN6_IPADDR_TO_V4MAPPED(dstaddr, &connp->conn_faddr_v6);
+	connp->conn_fport = dstport;
+
+	if (dccp->dccp_state == DCCPS_CLOSED) {
+		lport = dccp_update_next_port(dccps->dccps_next_port_to_try,
+		    dccp, B_TRUE);
+		lport = dccp_bindi(dccp, lport, &connp->conn_laddr_v6, 0,
+		    B_TRUE, B_FALSE, B_FALSE);
+
+		if (lport == 0) {
+			return (-TNOADDR);
+		}
+	}
+
+	error = dccp_set_destination(dccp);
+	if (error != 0) {
+		return (error);
+	}
+
+	/*
+	 * Don't connect to oneself.
+	 */
+	if (connp->conn_faddr_v4 == connp->conn_laddr_v4 &&
+	    connp->conn_fport == connp->conn_lport) {
+		return (-TBADADDR);
+	}
+
+	/* XXX state */
+
+	return (ipcl_conn_insert_v4(connp));
+}
+
+/*
+ * IPv6 connect.
+ */
+static int
+dccp_connect_ipv6(dccp_t *dccp, in6_addr_t *dstaddrp, in_port_t dstport,
+    uint32_t flowinfo, uint_t srcid, uint32_t scope_id)
+{
+	cmn_err(CE_NOTE, "dccp.c: dccp_connect_ipv6");
+
+	return (0);
+}
+
+/*
+ * Set the ports via conn_connect and build the template
+ * headers.
+ */
+int
+dccp_set_destination(dccp_t *dccp)
+{
+	conn_t		*connp = dccp->dccp_connp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	iulp_t		uinfo;
+	uint32_t	flags;
+	int		error;
+
+	flags = IPDF_LSO | IPDF_ZCOPY;
+	flags |= IPDF_UNIQUE_DCE;
+
+	mutex_enter(&connp->conn_lock);
+	error = conn_connect(connp, &uinfo, flags);
+	mutex_exit(&connp->conn_lock);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "conn_connect failed");
+		return (error);
+	}
+
+	error = dccp_build_hdrs(dccp);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "dccp_build_hdrs failed");
+		return (error);
+	}
+
+	/* XXX */
+
+	mutex_enter(&connp->conn_lock);
+	connp->conn_state_flags &= ~CONN_INCIPIENT;
+	mutex_exit(&connp->conn_lock);
+
+	return (0);
+}
