--- /dev/null	2012-06-13 12:04:35.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_output.c	2012-06-13 12:04:35.810109899 +0000
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ */
+
+/*
+ * Functions related to the output path.
+ */
+
+#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"
+#include "dccp_stack.h"
+
+static void	dccp_xmit_early_reset(char *, mblk_t *, uint32_t, uint32_t,
+		    int, ip_recv_attr_t *, ip_stack_t *, conn_t *);
+static boolean_t	dccp_send_rst_chk(dccp_stack_t *);
+
+/*
+ * STREAMS
+ */
+void
+dccp_wput(queue_t *q, mblk_t *mp)
+{
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_wput\n");
+}
+
+/*
+ * Send a reset as response to an incoming packet or
+ * reset a connection.
+ */
+void
+dccp_xmit_listeners_reset(mblk_t *mp, ip_recv_attr_t *ira, ip_stack_t *ipst,
+    conn_t *connp)
+{
+	dccpha_t	*dccpha;
+	uint32_t	seg_seq;
+	uint32_t	seg_ack;
+	uint32_t	seq_len;
+	uint_t		ip_hdr_len = ira->ira_ip_hdr_length;
+	uchar_t		*rptr;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
+
+	rptr = mp->b_rptr;
+
+	dccpha = (dccpha_t *)&rptr[ip_hdr_len];
+
+	//seg_seq = ntonl(dccpha->dha_seq);
+	//seg_ack = htonl(dccpha->dha_ack);
+
+	seq_len = msgdsize(mp) - (ip_hdr_len);
+
+	dccp_xmit_early_reset("no dccp, reset", mp, 0,
+	    0, 0, ira, ipst, connp);
+}
+
+/*
+ * RFC 4340, Section 8.1.3
+ */
+static void
+dccp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, uint32_t ack, int ctl,
+    ip_recv_attr_t *ira, ip_stack_t *ipst, conn_t *connp)
+{
+	dccpha_t	*dccpha;
+	dccpha_t	*nmp_dccpha;
+	dccpha_ack_t	*nmp_dccpha_ack;
+	dccpha_reset_t	*dccpha_reset;
+	dccpha_reset_t	*nmp_dccpha_reset;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ext_t	*nmp_dccpha_ext;
+	netstack_t	*ns = ipst->ips_netstack;
+	dccp_stack_t	*dccps = ns->netstack_dccp;
+	ip6_t		*ip6h;
+	ipha_t		*ipha;
+	ipha_t		*nmp_ipha;
+	ip_xmit_attr_t	ixas;
+	ip_xmit_attr_t	*ixa;
+	in6_addr_t	v6addr;
+	ipaddr_t	v4addr;
+	mblk_t		*nmp;
+	uint64_t	pkt_ack;
+	uint_t		ip_hdr_len = ira->ira_ip_hdr_length;
+	ushort_t	port;
+	ushort_t	len;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_early_reset");
+
+	if (!dccp_send_rst_chk(dccps)) {
+		cmn_err(CE_NOTE, "dccp_output.c: not sending reset packet");
+		DCCP_STAT(dccps, dccp_rst_unsent);
+		freemsg(mp);
+		return;
+	}
+
+		bzero(&ixas, sizeof (ixas));
+		ixa = &ixas;
+
+		ixa->ixa_flags |= IXAF_SET_ULP_CKSUM | IXAF_VERIFY_SOURCE;
+		ixa->ixa_protocol = IPPROTO_DCCP;
+		ixa->ixa_zoneid = ira->ira_zoneid;
+		ixa->ixa_ifindex = 0;
+		ixa->ixa_ipst = ipst;
+		ixa->ixa_cred = kcred;
+		ixa->ixa_cpid = NOPID;
+
+	if (str && dccps->dccps_dbg) {
+		(void) strlog(DCCP_MOD_ID, 0, 1, SL_TRACE,
+		    "dccp_xmit_early_reset: '%s', seq 0x%x, ack 0x%x, "
+		    "flags 0x%x",
+		    str, seq, ack, ctl);
+	}
+
+	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
+		ipha = (ipha_t *)mp->b_rptr;
+
+	} else {
+		/* XXX */
+	}
+
+	/*
+	 * Allocate a new DCCP reset message
+	 */
+	len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
+	nmp = allocb(len, BPRI_MED);
+	if (nmp == NULL) {
+		cmn_err(CE_NOTE, "alloc failed");
+		return;
+	}
+	bcopy(mp->b_rptr, nmp->b_wptr, ip_hdr_len + sizeof (dccpha_t));
+
+	nmp_dccpha = (dccpha_t *)&nmp->b_rptr[ip_hdr_len];
+	nmp_dccpha->dha_offset = 7;
+
+	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
+		nmp_ipha = (ipha_t *)nmp->b_rptr;
+
+		nmp_ipha->ipha_length = htons(len);
+		nmp_ipha->ipha_src = ipha->ipha_dst;
+		nmp_ipha->ipha_dst = ipha->ipha_src;
+
+		ixa->ixa_flags |= IXAF_IS_IPV4;
+		ixa->ixa_ip_hdr_length = ip_hdr_len;
+	} else {
+		cmn_err(CE_NOTE, "not v4");
+	}
+
+	dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
+
+	nmp->b_wptr = &nmp->b_rptr[len];
+
+	ixa->ixa_pktlen = len; // ?
+
+	nmp_dccpha->dha_fport = dccpha->dha_lport;
+	nmp_dccpha->dha_lport = dccpha->dha_fport;
+	nmp_dccpha->dha_type = DCCP_PKT_RESET;
+	nmp_dccpha->dha_x = 1;
+	nmp_dccpha->dha_res_seq = 0;
+	nmp_dccpha->dha_seq = 0;
+
+	nmp_dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
+
+	dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
+	nmp_dccpha_ext = (dccpha_ext_t *)&nmp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
+	nmp_dccpha_ext->dha_ext_seq = 0;
+
+	len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t);
+	nmp_dccpha_ack = (dccpha_ack_t *)&nmp->b_rptr[len];
+	nmp_dccpha_ack->dha_ack_high = dccpha->dha_seq;
+	nmp_dccpha_ack->dha_ack_low = dccpha_ext->dha_ext_seq;
+
+	len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t);
+	nmp_dccpha_reset = (dccpha_reset_t *)&nmp->b_rptr[len];
+	nmp_dccpha_reset->dha_reset_code = 7;
+	nmp_dccpha_reset->dha_reset_data[0] = 0;
+	nmp_dccpha_reset->dha_reset_data[1] = 0;
+	nmp_dccpha_reset->dha_reset_data[2] = 0;
+
+	(void) ip_output_simple(nmp, ixa);
+
+	ixa_cleanup(ixa);
+}
+
+/*
+ *
+ */
+static boolean_t
+dccp_send_rst_chk(dccp_stack_t *dccps)
+{
+	int64_t	now;
+
+	if (dccps->dccps_rst_sent_rate_enabled != 0) {
+		now = ddi_get_lbolt64();
+		if (TICK_TO_MSEC(now - dccps->dccps_last_rst_intrvl) >
+		    1 * SECONDS) {
+			dccps->dccps_last_rst_intrvl = now;
+			dccps->dccps_rst_cnt = 1;
+		} else if (++dccps->dccps_rst_cnt > dccps->dccps_rst_sent_rate) {
+			return (B_FALSE);
+		}
+	}
+
+	return (B_TRUE);
+}
+
+void
+dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
+{
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
+}
+
+mblk_t *
+dccp_xmit_mp(dccp_t *dccp, mblk_t *mp, int32_t max_to_send, int32_t *offset,
+    mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len,
+    boolean_t rexmit)
+{
+	conn_t		*connp = dccp->dccp_connp;
+	dccp_stack_t	*dccps = dccp->dccp_dccps;
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ack_t	*dccpha_ack;
+	dccpha_srv_t	*dccpha_srv;
+	ip_xmit_attr_t	*ixa = connp->conn_ixa;
+	mblk_t		*mp1;
+	uchar_t		*rptr;
+	ushort_t	len;
+	int		data_length;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_mp");
+
+	// dccpha_t already in iphc_len?
+	len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
+
+	//mp1 = dccp_generate_packet(connp, mp);
+	mp1 = allocb(len, BPRI_MED);
+	if (mp1 == NULL) {
+		cmn_err(CE_NOTE, "allocb failed");
+		return (NULL);
+	}
+
+	data_length = 0;
+
+	rptr = mp1->b_rptr;
+	mp1->b_wptr = &mp1->b_rptr[len];
+	bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+	dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
+	dccpha->dha_type = DCCP_PKT_RESPONSE;
+	dccpha->dha_offset = 8;
+	dccpha->dha_x = 1;
+	dccpha->dha_ccval = 0;
+	dccpha->dha_cscov = 0;
+	dccpha->dha_reserved = 0;
+	dccpha->dha_res_seq = 0;
+	dccpha->dha_seq = 0;
+
+	dccpha_ext = (dccpha_ext_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t)];
+	dccpha_ext->dha_ext_seq = 0;
+
+	dccpha_ack = (dccpha_ack_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
+	dccpha_ack->dha_ack_reserved = 0;
+	dccpha_ack->dha_ack_high = 0;
+	dccpha_ack->dha_ack_low = 0;
+
+	dccpha_srv = (dccpha_srv_t *)&rptr[ixa->ixa_ip_hdr_length + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
+	dccpha_srv->dha_srv_code = 0;
+
+	return (mp1);
+}
+
+mblk_t *
+dccp_generate_packet(conn_t *connp, mblk_t *mp)
+{
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ack_t	*dccpha_ack;
+	mblk_t		*mp1;
+	uint16_t	ack_high;
+	uint32_t	ack_low;
+//	uint_t          ip_hdr_len = ira->ira_ip_hdr_length;
+	ip_xmit_attr_t  *ixa = connp->conn_ixa;
+	uint_t		ip_hdr_len;
+	uint_t		len;
+	uchar_t		*rptr;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_packet");
+
+	ip_hdr_len = ixa->ixa_ip_hdr_length;
+
+	if (mp == NULL) {
+		cmn_err(CE_NOTE, "NULL pointer mp");
+		return (NULL);
+	}
+
+	dccpha = (dccpha_t *)&mp->b_rptr[ip_hdr_len];
+	dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
+
+	ack_high = dccpha->dha_seq;
+	ack_low = dccpha_ext->dha_ext_seq;
+
+	len = connp->conn_ht_iphc_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
+	//len = ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4;
+	mp1 = allocb(len, BPRI_MED);
+	if (mp1 == NULL) {
+		cmn_err(CE_NOTE, "allocb failed");
+		return (NULL);
+	}
+
+        rptr = mp1->b_rptr;
+        mp1->b_wptr = &mp1->b_rptr[len];
+
+        bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+        dccpha = (dccpha_t *)&rptr[ixa->ixa_ip_hdr_length];
+	//dccpha = (dccpha_t *)&mp1->b_rptr[ip_hdr_len];
+
+        dccpha->dha_type = DCCP_PKT_RESPONSE;
+        dccpha->dha_offset = 8;
+        dccpha->dha_x = 1;
+        dccpha->dha_ccval = 0;
+        dccpha->dha_cscov = 0;
+        dccpha->dha_reserved = 0;
+	dccpha->dha_res_seq = 0;
+	dccpha->dha_seq = 1;
+	dccpha->dha_sum = htons(len);
+
+	dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
+	dccpha_ext->dha_ext_seq = 1;
+
+	dccpha_ack = (dccpha_ack_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t)];
+	dccpha_ack->dha_ack_high = ack_high;
+	dccpha_ack->dha_ack_low = ack_low;
+
+	return (mp1);
+}
