--- /dev/null	2012-08-08 12:42:11.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_socket.c	2012-08-08 12:42:10.986144848 +0000
@@ -0,0 +1,694 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains function related to the socket interface.
+ */
+
+#include <sys/types.h>
+#include <sys/strlog.h>
+#include <sys/policy.h>
+#include <sys/sockio.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#define	_SUN_TPI_VERSION 2
+#include <sys/tihdr.h>
+#include <sys/squeue_impl.h>
+#include <sys/squeue.h>
+#include <sys/socketvar.h>
+
+#include <inet/common.h>
+#include <inet/dccp_impl.h>
+#include <inet/dccp_stack.h>
+#include <inet/proto_set.h>
+#include <inet/ip.h>
+
+#include <sys/cmn_err.h>
+
+static void	dccp_activate(sock_lower_handle_t, sock_upper_handle_t,
+		    sock_upcalls_t *, int, cred_t *);
+static int	dccp_accept(sock_lower_handle_t, sock_lower_handle_t,
+		    sock_upper_handle_t, cred_t *);
+static int	dccp_bind(sock_lower_handle_t, struct sockaddr *,
+		    socklen_t, cred_t *);
+static int	dccp_listen(sock_lower_handle_t, int, cred_t *);
+static int	dccp_connect(sock_lower_handle_t, const struct sockaddr *,
+		    socklen_t, sock_connid_t *, cred_t *);
+static int	dccp_getpeername(sock_lower_handle_t, struct sockaddr *,
+		    socklen_t *, cred_t *);
+static int	dccp_getsockname(sock_lower_handle_t, struct sockaddr *,
+		    socklen_t *, cred_t *);
+static int	dccp_getsockopt(sock_lower_handle_t, int, int, void *,
+		    socklen_t *, cred_t *);
+static int	dccp_setsockopt(sock_lower_handle_t, int, int, const void *,
+		    socklen_t, cred_t *);
+static int	dccp_send(sock_lower_handle_t, mblk_t *, struct nmsghdr *,
+		    cred_t *);
+static int	dccp_shutdown(sock_lower_handle_t, int, cred_t *);
+static void	dccp_clr_flowctrl(sock_lower_handle_t);
+static int	dccp_ioctl(sock_lower_handle_t, int, intptr_t, int, int32_t *,
+		    cred_t *);
+static int	dccp_close(sock_lower_handle_t, int, cred_t *);
+
+sock_downcalls_t sock_dccp_downcalls = {
+	dccp_activate,		/* sd_activate */
+	dccp_accept,		/* sd_accept */
+	dccp_bind,		/* sd_bind */
+	dccp_listen,		/* sd_listen */
+	dccp_connect,		/* sd_connect */
+	dccp_getpeername,	/* sd_getpeername */
+	dccp_getsockname,	/* sd_getsockname */
+	dccp_getsockopt,	/* sd_getsockopt */
+	dccp_setsockopt,	/* sd_setsockopt */
+	dccp_send,		/* sd_send */
+	NULL,			/* sd_send_uio */
+	NULL,			/* sd_recv_uio */
+	NULL,			/* sd_poll */
+	dccp_shutdown,		/* sd_shutdown */
+	dccp_clr_flowctrl,	/* sd_setflowctrl */
+	dccp_ioctl,		/* sd_ioctl */
+	dccp_close,		/* sd_close */
+};
+
+/* ARGSUSED */
+static void
+dccp_activate(sock_lower_handle_t proto_handle, sock_upper_handle_t sock_handle,
+    sock_upcalls_t *sock_upcalls, int flags, cred_t *cr)
+{
+	conn_t *connp = (conn_t *)proto_handle;
+	struct sock_proto_props		sopp;
+	extern struct module_info	dccp_rinfo;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_activate");
+
+	ASSERT(connp->conn_upper_handle == NULL);
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	sopp.sopp_flags = SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT |
+	    SOCKOPT_MAXPSZ | SOCKOPT_MAXBLK | SOCKOPT_RCVTIMER |
+	    SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ;
+
+	sopp.sopp_rxhiwat = SOCKET_RECVHIWATER;
+	sopp.sopp_rxlowat = SOCKET_RECVLOWATER;
+	sopp.sopp_maxpsz = INFPSZ;
+	sopp.sopp_maxblk = INFPSZ;
+	sopp.sopp_rcvtimer = SOCKET_TIMER_INTERVAL;
+	sopp.sopp_rcvthresh = SOCKET_RECVHIWATER >> 3;
+	sopp.sopp_maxaddrlen = sizeof (sin6_t);
+	sopp.sopp_minpsz = (dccp_rinfo.mi_minpsz == 1) ? 0 :
+	    dccp_rinfo.mi_minpsz;
+
+	connp->conn_upcalls = sock_upcalls;
+	connp->conn_upper_handle = sock_handle;
+
+	/* XXX  conn_rcvbuf */
+	(*connp->conn_upcalls->su_set_proto_props)(connp->conn_upper_handle,
+	    &sopp);
+}
+
+/*ARGSUSED*/
+static int
+dccp_accept(sock_lower_handle_t lproto_handle,
+    sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle,
+    cred_t *cr)
+{
+	conn_t	*lconnp, *econnp;
+	dccp_t	*listener, *eager;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_accept");
+
+	econnp = (conn_t *)eproto_handle;
+	eager = econnp->conn_dccp;
+	ASSERT(IPCL_IS_NONSTR(econnp));
+	ASSERT(eager->dccp_listener != NULL);
+	listener = eager->dccp_listener;
+	lconnp = (conn_t *)listener->dccp_connp;
+	ASSERT(listener->dccp_state == DCCPS_LISTEN);
+	ASSERT(lconnp->conn_upper_handle != NULL);
+
+	ASSERT(econnp->conn_upper_handle == NULL ||
+	    econnp->conn_upper_handle == sock_handle);
+	ASSERT(econnp->conn_upcalls == NULL ||
+	    econnp->conn_upcalls == lconnp->conn_upcalls);
+	econnp->conn_upper_handle = sock_handle;
+	econnp->conn_upcalls = lconnp->conn_upcalls;
+
+	ASSERT(econnp->conn_netstack ==
+	    listener->dccp_connp->conn_netstack);
+	ASSERT(eager->dccp_dccps == listener->dccp_dccps);
+
+	ASSERT(econnp->conn_ref >= 2);
+	eager->dccp_listener = NULL; /* XXX */
+	CONN_DEC_REF(listener->dccp_connp);
+
+	return (0);
+}
+
+static int
+dccp_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa,
+    socklen_t len, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_bind");
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	error = squeue_synch_enter(connp, NULL);
+	if (error != 0) {
+		/* Failed to enter */
+		return (ENOSR);
+	}
+
+	/* Binding to NULL address means unbind */
+	if (sa == NULL) {
+		if (connp->conn_dccp->dccp_state < DCCPS_LISTEN) {
+			error = dccp_do_unbind(connp);
+		} else {
+			error = EINVAL;
+		}
+	} else {
+		error = dccp_do_bind(connp, sa, len, cr, B_TRUE);
+	}
+
+	squeue_synch_exit(connp);
+
+	if (error < 0) {
+		if (error == -TOUTSTATE) {
+			error = EINVAL;
+		} else {
+			error = proto_tlitosyserr(-error);
+		}
+	}
+
+	return (error);
+}
+
+/* ARGSUSED */
+static int
+dccp_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	dccp_t	*dccp = connp->conn_dccp;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_listen");
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	error = squeue_synch_enter(connp, NULL);
+	if (error != 0) {
+		/* Failed to enter */
+		return (ENOBUFS);
+	}
+
+	error = dccp_do_listen(connp, NULL, 0, backlog, cr, B_FALSE);
+	if (error == 0) {
+		/* XXX:DCCP */
+		(*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle,
+		    SOCK_OPCTL_ENAB_ACCEPT,
+		    (uintptr_t)(10));
+	} else if (error < 0) {
+		if (error == -TOUTSTATE) {
+			error = EINVAL;
+		} else {
+			error = proto_tlitosyserr(-error);
+		}
+	}
+
+	squeue_synch_exit(connp);
+
+	return (error);
+}
+
+static int
+dccp_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa,
+    socklen_t len, sock_connid_t *id, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_connect");
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	error = proto_verify_ip_addr(connp->conn_family, sa, len);
+	if (error != 0) {
+		return (error);
+	}
+
+	error = squeue_synch_enter(connp, NULL);
+	if (error != 0) {
+		/* Failed to enter */
+		return (ENOSR);
+	}
+
+	error = dccp_do_connect(connp, sa, len, cr, curproc->p_pid);
+	if (error == 0) {
+		*id = connp->conn_dccp->dccp_connid;
+	} else if (error < 0) {
+		if (error == -TOUTSTATE) {
+			switch (connp->conn_dccp->dccp_state) {
+			case DCCPS_REQUEST:
+				error = EALREADY;
+				break;
+			case DCCPS_PARTOPEN:
+				error = EISCONN;
+				break;
+			case DCCPS_LISTEN:
+				error = EOPNOTSUPP;
+				break;
+			default:
+				error = EINVAL;
+				break;
+			}
+		} else {
+			error = proto_tlitosyserr(-error);
+		}
+	}
+
+	squeue_synch_exit(connp);
+
+	cmn_err(CE_NOTE, "dccp_connect.c: exit %d", error);
+	return ((error == 0) ? EINPROGRESS : error);
+}
+
+/* ARGSUSED3 */
+static int
+dccp_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr,
+    socklen_t *addrlenp, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	dccp_t	*dccp = connp->conn_dccp;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_getpeername");
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	ASSERT(dccp != NULL);
+	if (dccp->dccp_state < DCCPS_OPEN) {
+		return (ENOTCONN);
+	}
+
+	return (conn_getpeername(connp, addr, addrlenp));
+}
+
+/* ARGSUSED3 */
+static int
+dccp_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr,
+    socklen_t *addrlenp, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockname");
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	/* XXX UDP has locks here, TCP not */
+	mutex_enter(&connp->conn_lock);
+	error = conn_getsockname(connp, addr, addrlenp);
+	mutex_exit(&connp->conn_lock);
+
+	return (error);
+}
+
+static int
+dccp_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name,
+    void *optvalp, socklen_t *optlen, cred_t *cr)
+{
+	conn_t		*connp = (conn_t *)proto_handle;
+	void		*optvalp_buf;
+	t_uscalar_t	max_optbuf_len;
+	int		len;
+	int		error;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_getsockopt");
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	error = proto_opt_check(level, option_name, *optlen, &max_optbuf_len,
+	    dccp_opt_obj.odb_opt_des_arr,
+	    dccp_opt_obj.odb_opt_arr_cnt,
+	    B_FALSE, B_TRUE, cr);
+	if (error != 0) {
+		if (error < 0) {
+			error = proto_tlitosyserr(-error);
+		}
+		return (error);
+	}
+
+	optvalp_buf = kmem_alloc(max_optbuf_len, KM_SLEEP);
+	if (optvalp_buf == NULL) {
+		return (ENOMEM);
+	}
+
+	error = squeue_synch_enter(connp, NULL);
+	if (error == ENOMEM) {
+		kmem_free(optvalp_buf, max_optbuf_len);
+		return (ENOMEM);
+	}
+
+	len = dccp_opt_get(connp, level, option_name, optvalp_buf);
+	squeue_synch_exit(connp);
+
+	if (len == -1) {
+		kmem_free(optvalp_buf, max_optbuf_len);
+		return (EINVAL);
+	}
+
+	t_uscalar_t size = MIN(len, *optlen);
+
+	bcopy(optvalp_buf, optvalp, size);
+	bcopy(&size, optlen, sizeof (size));
+
+	kmem_free(optvalp_buf, max_optbuf_len);
+
+	return (0);
+}
+
+static int
+dccp_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name,
+    const void *optvalp, socklen_t optlen, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_setsockopt");
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	error = squeue_synch_enter(connp, NULL);
+	if (error == ENOMEM) {
+		return (ENOMEM);
+	}
+
+	error = proto_opt_check(level, option_name, optlen, NULL,
+	    dccp_opt_obj.odb_opt_des_arr,
+	    dccp_opt_obj.odb_opt_arr_cnt,
+	    B_TRUE, B_FALSE, cr);
+	if (error != 0) {
+		if (error < 0) {
+			error = proto_tlitosyserr(-error);
+		}
+		squeue_synch_exit(connp);
+		return (error);
+	}
+
+	error = dccp_opt_set(connp, SETFN_OPTCOM_NEGOTIATE, level, option_name,
+	    optlen, (uchar_t *)optvalp, (uint_t *)&optlen, (uchar_t *)optvalp,
+	    NULL, cr);
+	squeue_synch_exit(connp);
+
+	ASSERT(error >= 0);
+
+	return (error);
+}
+
+/* ARGSUSED */
+static int
+dccp_send(sock_lower_handle_t proto_handle, mblk_t *mp, struct nmsghdr *msg,
+    cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	dccp_t	*dccp;
+	uint32_t msize;
+	int32_t	dccpstate;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_send");
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	ASSERT(connp->conn_ref >= 2);
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	if (msg->msg_controllen != 0) {
+		freemsg(mp);
+		return (EOPNOTSUPP);
+	}
+
+	switch (DB_TYPE(mp)) {
+	case M_DATA:
+		dccp = connp->conn_dccp;
+		ASSERT(dccp != NULL);
+
+		dccpstate = dccp->dccp_state;
+		if (dccpstate < DCCPS_OPEN) {
+			freemsg(mp);
+
+			return ((dccpstate == DCCPS_REQUEST) ? ENOTCONN :
+			    ((dccp->dccp_connid > 0) ? EPIPE : ENOTCONN));
+		} else if (dccpstate > DCCPS_CLOSING) {
+			freemsg(mp);
+			return (EPIPE);
+		}
+
+		/* XXX */
+
+		msize = msgdsize(mp);
+
+		CONN_INC_REF(connp);
+
+		if (msg->msg_flags & MSG_OOB) {
+			SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output_urgent,
+			    connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT); 
+		} else {
+			SQUEUE_ENTER_ONE(connp->conn_sqp, mp, dccp_output,
+			    connp, NULL, dccp_squeue_flag, SQTAG_DCCP_OUTPUT);
+		}
+
+		return (0);
+
+	default:
+		ASSERT(0);
+	}
+
+	freemsg(mp);
+
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+dccp_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	dccp_t	*dccp = connp->conn_dccp;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_shutdown");
+
+	/* All Solaris components should pass a cred for this operation. */
+	ASSERT(cr != NULL);
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+
+	return (ENOTSUP);
+}
+
+static void
+dccp_clr_flowctrl(sock_lower_handle_t proto_handle)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	dccp_t	*dccp = connp->conn_dccp;
+	mblk_t	*mp;
+	int	error;
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_clr_flowctrl");
+
+	error = squeue_synch_enter(connp, mp);
+
+	squeue_synch_exit(connp);
+}
+
+/* ARGSUSED */
+static int
+dccp_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg,
+    int mode, int32_t *rvalp, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_ioctl");
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	/* All Solaris components should pass a cred for this operation. */
+	ASSERT(cr != NULL);
+
+	return (ENOTSUP);
+}
+
+/* ARGSUSED */
+static int
+dccp_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr)
+{
+	conn_t	*connp = (conn_t *)proto_handle;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_close\n");
+
+	ASSERT(connp->conn_upper_handle != NULL);
+
+	/* All Solaris components should pass a cred for this operation */
+	ASSERT(cr != NULL);
+
+	dccp_close_common(connp, flags);
+
+	ip_free_helper_stream(connp);
+
+	CONN_DEC_REF(connp);
+
+	/*
+	 * EINPROGRESS tells sockfs to wait for a 'closed' upcall before
+	 * freeing the socket.
+	 */
+	return (EINPROGRESS);
+}
+
+
+/*
+ * Socket create function.
+ */
+sock_lower_handle_t
+dccp_create(int family, int type, int proto, sock_downcalls_t **sockdowncalls,
+    uint_t *smodep, int *errorp, int flags, cred_t *credp)
+{
+	conn_t		*connp;
+	boolean_t	isv6;
+
+	/* XXX (type != SOCK_STREAM */
+	if ((family != AF_INET && family != AF_INET6) ||
+	    (proto != 0 && proto != IPPROTO_DCCP)) {
+		*errorp = EPROTONOSUPPORT;
+		return (NULL);
+	}
+
+	cmn_err(CE_NOTE, "dccp_socket: dccp_create\n");
+
+	isv6 = family == AF_INET6 ? B_TRUE: B_FALSE;
+	connp = dccp_create_common(credp, isv6, B_TRUE, errorp);
+	if (connp == NULL) {
+		return (NULL);
+	}
+
+	/*
+	 * Increment ref for DCCP connection.
+	 */
+	mutex_enter(&connp->conn_lock);
+	CONN_INC_REF_LOCKED(connp);
+	ASSERT(connp->conn_ref == 2);
+	connp->conn_state_flags &= ~CONN_INCIPIENT;
+	connp->conn_flags |= IPCL_NONSTR;
+	mutex_exit(&connp->conn_lock);
+
+	ASSERT(errorp != NULL);
+	*errorp = 0;
+	*sockdowncalls = &sock_dccp_downcalls;
+	*smodep = SM_CONNREQUIRED | SM_EXDATA | SM_ACCEPTSUPP |
+	    SM_SENDFILESUPP;
+
+	return ((sock_lower_handle_t)connp);
+}
+
+int
+dccp_fallback(sock_lower_handle_t proto_handle, queue_t *q,
+    boolean_t issocket, so_proto_quiesced_cb_t quiesced_cb,
+    sock_quiesce_arg_t *arg)
+{
+	cmn_err(CE_NOTE, "dccp_socket: dccp_fallback\n");
+
+	return (0);
+}
+
+/*
+ * Notifies a non-STREAMS based listener about a new connection. This
+ * function is executed on the *eager*'s squeue once the 3 way handshake
+ * has completed. Note that the behavior differs from STREAMS, where the
+ * T_CONN_IND is sent up by tcp_send_conn_ind() while on the *listener*'s
+ * squeue.
+ *
+ * Returns B_TRUE if the notification succeeded and an upper handle was
+ * obtained. `tcp' should be closed on failure.
+ */
+boolean_t
+dccp_newconn_notify(dccp_t *dccp, ip_recv_attr_t *ira)
+{
+	dccp_t			*listener = dccp->dccp_listener;
+	dccp_t			*tail;
+	conn_t			*lconnp = listener->dccp_connp;
+	conn_t			*econnp = dccp->dccp_connp;
+	ipaddr_t		*addr_cache;
+	sock_upper_handle_t	upper;
+	struct sock_proto_props	sopp;
+
+	cmn_err(CE_NOTE, "dccp_socket.c: dccp_newconn_notify");
+
+	if (lconnp->conn_upcalls) {
+		cmn_err(CE_NOTE, "NOT NULL");
+	} else {
+		cmn_err(CE_NOTE, "ISSSSSS NULL");
+	}
+
+	if ((upper = (*lconnp->conn_upcalls->su_newconn)
+		(lconnp->conn_upper_handle, (sock_lower_handle_t)econnp,
+		&sock_dccp_downcalls, ira->ira_cred, ira->ira_cpid,
+		&econnp->conn_upcalls)) == NULL) {
+			return (B_FALSE);
+	}
+	econnp->conn_upper_handle = upper;
+
+	(*econnp->conn_upcalls->su_set_proto_props)
+	    (econnp->conn_upper_handle, &sopp);
+
+	return (B_TRUE);
+}
