--- /dev/null	2012-08-18 10:37:11.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_tpi.c	2012-08-18 10:37:11.357947486 +0000
@@ -0,0 +1,434 @@
+/*
+ * 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
+ */
+
+/*
+ * Functions related to TPI.
+ */
+
+#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 <inet/proto_set.h>
+
+#include <sys/cmn_err.h>
+
+
+/*
+ * This file contains functions related to the TPI interface.
+ */
+
+/*
+ * XXX
+ */
+static void
+dccp_copy_info(struct T_info_ack *tia, dccp_t *dccp)
+{
+	conn_t		*connp = dccp->dccp_connp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	extern struct T_info_ack dccp_g_t_info_ack;
+	extern struct T_info_ack dccp_g_t_info_ack_v6;
+
+	if (connp->conn_family == AF_INET6) {
+		*tia = dccp_g_t_info_ack_v6;
+	} else {
+		*tia = dccp_g_t_info_ack;
+	}
+
+	/* XXX */
+}
+
+/*
+ * XXX
+ */
+void
+dccp_do_capability_ack(dccp_t *dccp, struct T_capability_ack *tcap,
+    t_uscalar_t cap_bits1)
+{
+	tcap->CAP_bits1 = 0;
+
+	if (cap_bits1 & TC1_INFO) {
+		dccp_copy_info(&tcap->INFO_ack, dccp);
+		tcap->CAP_bits1 |= TC1_INFO;
+	}
+
+	if (cap_bits1 & TC1_ACCEPTOR_ID) {
+		tcap->ACCEPTOR_id = dccp->dccp_acceptor_id;
+		tcap->CAP_bits1 |= TC1_ACCEPTOR_ID;
+	}
+}
+
+/*
+ * This routine responds to T_CAPABILITY_REQ messages.
+ */
+void
+dccp_capability_req(dccp_t *dccp, mblk_t *mp)
+{
+	struct T_capability_ack	*tcap;
+	t_uscalar_t		cap_bits1;
+
+	if (MBLKL(mp) < sizeof (struct T_capability_req)) {
+		freemsg(mp);
+		return;
+	}
+
+	cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1;
+
+	mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
+	    mp->b_datap->db_type, T_CAPABILITY_ACK);
+	if (mp == NULL) {
+		return;
+	}
+
+	tcap = (struct T_capability_ack *)mp->b_rptr;
+	dccp_do_capability_ack(dccp, tcap, cap_bits1);
+
+	putnext(dccp->dccp_connp->conn_rq, mp);
+}
+
+/*
+ * This routine responds to T_INFO_REQ messages.
+ */
+void
+dccp_info_req(dccp_t *dccp, mblk_t *mp)
+{
+	mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO,
+	    T_INFO_ACK);
+	if (mp == NULL) {
+		dccp_err_ack(dccp, mp, TSYSERR, ENOMEM);
+		return;
+	}
+
+	dccp_copy_info((struct T_info_ack *)mp->b_rptr, dccp);
+	putnext(dccp->dccp_connp->conn_rq, mp);
+}
+
+/*
+ * This routine responds to T_ADDR_REQ messages.
+ */
+void
+dccp_addr_req(dccp_t *dccp, mblk_t *mp)
+{
+	conn_t	*connp = dccp->dccp_connp;
+	mblk_t	*ackmp;
+	uint_t	addrlen;
+	struct sockaddr		*sa;
+	struct T_addr_ack	*taa;
+
+	/* XXX */
+}
+
+/*
+ * Helper function to generate TPI errors acks.
+ */
+void
+dccp_err_ack(dccp_t *dccp, mblk_t *mp, int t_error, int sys_error)
+{
+	if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) {
+		putnext(dccp->dccp_connp->conn_rq, mp);
+	}
+}
+
+void
+dccp_tpi_connect(dccp_t *dccp, mblk_t *mp)
+{
+	conn_t			*connp = dccp->dccp_connp;
+	queue_t			*q = connp->conn_wq;
+	struct sockaddr		*sa;
+	struct T_conn_req	*tcr;
+	sin_t			*sin;
+	sin6_t			*sin6;
+	cred_t			*cr;
+	pid_t			cpid;
+	socklen_t		len;
+	int			error;
+
+	cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_connect");
+
+	cr = msg_getcred(mp, &cpid);
+	ASSERT(cr != NULL);
+	if (cr == NULL) {
+		dccp_err_ack(dccp, mp, TSYSERR, EINVAL);
+		return;
+	}
+
+	tcr = (struct T_conn_req *)mp->b_rptr;
+
+	ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
+	if ((mp->b_wptr - mp->b_rptr) < sizeof (*tcr)) {
+		dccp_err_ack(dccp, mp, TPROTO, 0);
+		return;
+	}
+
+	error = proto_verify_ip_addr(connp->conn_family, sa, len);
+	if (error != 0) {
+		dccp_err_ack(dccp, mp, TSYSERR, 0);
+		return;
+	}
+
+	error = dccp_do_connect(dccp->dccp_connp, sa, len, cr, cpid);
+	if (error < 0) {
+		mp = mi_tpi_err_ack_alloc(mp, -error, 0);
+	} else if (error > 0) {
+		mp = mi_tpi_err_ack_alloc(mp, TSYSERR, error);
+	} else {
+		mp = mi_tpi_ok_ack_alloc(mp);
+	}
+}
+
+int
+dccp_tpi_close(queue_t *q, int flags)
+{
+	conn_t	*connp;
+
+	ASSERT(WR(q)->q_next == NULL);
+
+	connp = Q_TO_CONN(q);
+
+	dccp_close_common(connp, flags);
+
+	qprocsoff(q);
+	inet_minor_free(connp->conn_minor_arena, connp->conn_dev);
+
+	return (0);
+}
+
+int
+dccp_tpi_close_accept(queue_t *q)
+{
+	vmem_t	*minor_arena;
+	dev_t	conn_dev;
+
+	cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_close_accept");
+
+	return (0);
+}
+
+boolean_t
+dccp_conn_con(dccp_t *dccp, uchar_t *iphdr, mblk_t *idmp,
+    mblk_t **defermp, ip_recv_attr_t *ira)
+{
+	conn_t	*connp = dccp->dccp_connp;
+	sin_t	sin;
+	sin6_t	sin6;
+	mblk_t	*mp;
+	char	*optp = NULL;
+	int	optlen = 0;
+
+	cmn_err(CE_NOTE, "dccp_tpi.c: dccp_conn_con");
+
+	if (defermp != NULL) {
+		*defermp = NULL;
+	}
+
+	if (IPH_HDR_VERSION(iphdr) == IPV4_VERSION) {
+		/* Packet is IPv4 */
+		if (connp->conn_family == AF_INET) {
+			sin = sin_null;
+			sin.sin_addr.s_addr = connp->conn_faddr_v4;
+			sin.sin_port = connp->conn_fport;
+			sin.sin_family = AF_INET;
+			mp = mi_tpi_conn_con(NULL, (char *)&sin,
+			    (int)sizeof (sin_t), optp, optlen);
+		} else {
+			sin6 = sin6_null;
+			sin6.sin6_addr = connp->conn_faddr_v6;
+			sin6.sin6_port = connp->conn_fport;
+			sin6.sin6_family = AF_INET6;
+			mp = mi_tpi_conn_con(NULL, (char *)&sin6,
+			    (int)sizeof (sin6_t), optp, optlen);
+		}
+	} else {
+		ip6_t	*ip6h = (ip6_t *)iphdr;
+
+		ASSERT(IPH_HDR_VERSION(iphdr) == IPV6_VERSION);
+		ASSERT(connp->conn_family == AF_INET6);
+
+		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;
+		mp = mi_tpi_conn_con(NULL, (char *)&sin6,
+		    (int)sizeof (sin6_t), optp, optlen);
+	}
+
+	if (!mp) {
+		return (B_FALSE);
+	}
+
+	mblk_copycred(mp, idmp);
+
+	if (defermp == NULL) {
+		if (IPCL_IS_NONSTR(connp)) {
+			cmn_err(CE_NOTE, "calling su_connected");
+			(*connp->conn_upcalls->su_connected)
+			    (connp->conn_upper_handle, dccp->dccp_connid,
+			    ira->ira_cred, ira->ira_cpid);
+			freemsg(mp);
+		} else {
+			if (ira->ira_cred != NULL) {
+				/* So that getpeerucred works for TPI sockfs */
+				mblk_setcred(mp, ira->ira_cred, ira->ira_cpid);
+			}
+			putnext(connp->conn_rq, mp);
+		}
+	} else {
+		*defermp = mp;
+	}
+
+	/* XXX */
+	return (B_TRUE);
+}
+
+/*
+ * Routine to get the values of options.
+ */
+int
+dccp_tpi_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
+{
+	return (dccp_opt_get(Q_TO_CONN(q), level, name, ptr));
+}
+
+/*
+ * Routine to set the values of options.
+ */
+/* ARGSUSED */
+int
+dccp_tpi_opt_set(queue_t *q, uint_t optset_context, int level, int name,
+    uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
+    void *thisdg_attrs, cred_t *cr)
+{
+	conn_t	*connp =  Q_TO_CONN(q);
+
+	return (dccp_opt_set(connp, optset_context, level, name, inlen, invalp,
+	    outlenp, outvalp, thisdg_attrs, cr));
+}
+
+void
+dccp_tpi_accept(queue_t *q, mblk_t *mp)
+{
+	struct T_ok_ack		*ok;
+	struct T_conn_res	*conn_res;
+	conn_t			*econnp;
+	dccp_t			*eager;
+	dccp_t			*listener;
+	queue_t			*rq = RD(q);
+	mblk_t			*discon_mp;
+	cred_t			*cr;
+
+	cmn_err(CE_NOTE, "dccp_tpi.c: dccp_tpi_accept");
+
+	ASSERT(DB_TYPE(mp) == M_PROTO);
+
+	cr = msg_getcred(mp, NULL);
+	ASSERT(cr != NULL);
+	if (cr == NULL) {
+		mp = mi_tpi_err_ack_alloc(mp, TSYSERR, EINVAL);
+		if (mp != NULL) {
+			putnext(rq, mp);
+		}
+		return;
+	}
+
+	conn_res = (struct T_conn_res *)mp->b_rptr;
+	ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
+	if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_conn_res)) {
+		mp = mi_tpi_err_ack_alloc(mp, TPROTO, 0);
+		if (mp != NULL) {
+			putnext(rq, mp);
+		}
+		return;
+	}
+
+	switch (conn_res->PRIM_type) {
+	case O_T_CONN_RES:
+	case T_CONN_RES:
+		putnext(rq, mp);
+		return;
+	default:
+		mp = mi_tpi_err_ack_alloc(mp, TNOTSUPPORT, 0);
+		if (mp != NULL) {
+			putnext(rq, mp);
+		}
+		return;
+	}
+}
+
+static void
+dccp_accept_swap(dccp_t *listener, dccp_t *acceptor, dccp_t *eager)
+{
+	conn_t	*econnp;
+	conn_t	*aconnp;
+}
+
+/*
+ * This runs at the tail end of accept processing on the squeue of the
+ * new connection.
+ */
+static void
+dccp_accept_finish(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
+{
+	conn_t		*connp = (conn_t *)arg;
+	dccp_t		*dccp = connp->conn_dccp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	queue_t		*q = connp->conn_rq;
+	struct stroptions	*stropt;
+	struct sock_proto_props	sopp;
+
+	/* Should never be called for non-STREAMS sockets */
+	ASSERT(!IPCL_IS_NONSTR(connp));
+
+	/* We should just receive a single mblk that fits a T_discon_ind */
+	ASSERT(mp->b_cont == NULL);
+
+	/* XXX */
+
+	dccp_get_proto_props(dccp, &sopp);
+
+	ASSERT(DB_REF(mp) == 1);
+	ASSERT(MBLKSIZE(mp) >= sizeof (struct stroptions));
+
+	DB_TYPE(mp) = M_SETOPTS;
+
+	/* XXX */
+
+	dccp->dccp_hard_binding = B_FALSE;
+
+	if (connp->conn_keepalive) {
+		dccp->dccp_ka_last_intrvl = 0;
+		dccp->dccp_ka_tid = DCCP_TIMER(dccp, dccp_keepalive_timer,
+		    dccp->dccp_ka_interval);
+	}
+}
