--- /dev/null	2012-08-18 10:37:10.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_output.c	2012-08-18 10:37:10.659456059 +0000
@@ -0,0 +1,1034 @@
+/*
+ * 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/dccp_impl.h>
+#include <inet/dccp_stack.h>
+#include <inet/ip.h>
+#include <inet/ipsec_impl.h>
+
+#include <sys/cmn_err.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 *);
+static int	dccp_xmit_end(dccp_t *);
+static mblk_t	*dccp_generate_common(conn_t *, uint8_t, uint_t);
+
+/*
+ * STREAMS
+ */
+void
+dccp_wput(queue_t *q, mblk_t *mp)
+{
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_wput");
+}
+
+/*
+ * Fast path write put.
+ */
+void
+dccp_wput_data(dccp_t *dccp, mblk_t *mp, boolean_t urgent)
+{
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_data");
+}
+
+/*
+ *
+ */
+void
+dccp_wput_sock(queue_t *wq, mblk_t *mp)
+{
+	conn_t	*connp = Q_TO_CONN(wq);
+	dccp_t	*dccp = connp->conn_dccp;
+	struct T_capability_req	*car = (struct T_capability_req *)mp->b_rptr;
+
+	cmn_err(CE_NOTE, "dccp_wput_sock");
+
+	ASSERT(wq->q_qinfo == &dccp_sock_winit);
+	wq->q_qinfo = &dccp_winit;
+
+	ASSERT(IPCL_IS_TCP(connp));
+	ASSERT(DCCP_IS_SOCKET(dccp));
+
+	if (DB_TYPE(mp) == M_PCPROTO &&
+	    MBLKL(mp) == sizeof (struct T_capability_req) &&
+	    car->PRIM_type == T_CAPABILITY_REQ) {
+		dccp_capability_req(dccp, mp);
+		return;
+	}
+
+	dccp_wput(wq, mp);
+}
+
+/* ARGSUSED */
+void
+dccp_wput_fallback(queue_t *eq, mblk_t *mp)
+{
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_wput_fallback");
+
+#ifdef DEBUG
+	cmn_err(CE_CONT, "tcp_wput_fallback: Message during fallback \n");
+#endif /* DEBUG */
+
+	freemsg(mp);
+}
+
+/*
+ * Initiate closedown sequence on an active connection.
+ */
+static int
+dccp_xmit_end(dccp_t *dccp)
+{
+	conn_t	*connp = dccp->dccp_connp;
+	mblk_t	*mp;
+
+	/* XXX */
+
+	return (0);
+}
+
+/*
+ * Output fast path.
+ */
+void
+dccp_output(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;
+	dccpha_t	*dccpha;
+	mblk_t		*mp1;
+	ip_xmit_attr_t	*ixa;
+	struct datab	*db;
+	uchar_t		*rptr;
+	uint32_t	msize;
+	uint32_t	sum;
+	int		len;
+	int		plen;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_output");
+
+	ASSERT((connp->conn_fanout != NULL && connp->conn_ref >= 4) ||
+	    (connp->conn_fanout == NULL && connp->conn_ref >= 3));
+
+	ASSERT(DB_TYPE(mp) == M_DATA);
+	msize = (mp->b_cont == NULL) ? MBLKL(mp) : msgdsize(mp);
+
+	ASSERT((uintptr_t)(mp->b_wptr - mp->b_rptr) <= (uintptr_t)INT_MAX);
+	len = (int)(mp->b_wptr - mp->b_rptr);
+
+	if ((mp->b_cont != NULL) ||
+	    (dccp->dccp_state != DCCPS_OPEN) ||
+	    (len == 0)) {
+		dccp_wput_data(dccp, mp, B_FALSE);
+		return;
+	}
+
+	mp1 = dupb(mp);
+	if (mp1 == NULL) {
+		goto no_memory;
+	}
+
+	/* Adjust header information */
+	dccpha = dccp->dccp_dccpha;
+
+	sum = len + connp->conn_ht_ulp_len + connp->conn_sum;
+	sum = (sum >> 16) + (sum & 0xffff);
+	dccpha->dha_sum = htons(sum);
+
+	DCCPS_BUMP_MIB(dccps, dccpOutDataSegs);
+	DCCPS_UPDATE_MIB(dccps, dccpOutDataBytes, len);
+	BUMP_LOCAL(dccp->dccp_obsegs);
+
+	plen = len + connp->conn_ht_iphc_len;
+
+	ixa = connp->conn_ixa;
+	ixa->ixa_pktlen = plen;
+
+	if (ixa->ixa_flags & IXAF_IS_IPV4) {
+		dccp->dccp_ipha->ipha_length = htons(plen);
+	} else {
+		dccp->dccp_ip6h->ip6_plen = htons(plen - IPV6_HDR_LEN);
+	}
+
+	rptr = mp1->b_rptr;
+	bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+
+	dccp_send_data(dccp, mp1);
+
+	return;
+
+no_memory:
+	return;
+}
+
+void
+dccp_output_urgent(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
+{
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_output_urgent");
+}
+
+void
+dccp_close_output(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;
+	char		*msg;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_close_output");
+
+	/*
+	 * When a non-STREAMS socket is being closed, it does not always
+	 * stick around waiting for tcp_close_output to run and can therefore
+	 * have dropped a reference already. So adjust the asserts accordingly.
+	 */
+	ASSERT((connp->conn_fanout != NULL &&
+	    connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 3 : 4)) ||
+	    (connp->conn_fanout == NULL &&
+	    connp->conn_ref >= (IPCL_IS_NONSTR(connp) ? 2 : 3)));
+
+	msg = NULL;
+	switch (dccp->dccp_state) {
+	case DCCPS_CLOSED:
+		break;
+	case DCCPS_BOUND:
+		break;
+	case DCCPS_REQUEST:
+		msg = "dccp_close, during connect";
+		break;
+	case DCCPS_RESPOND:
+		/* FALLTHRU */
+	default:
+		/*
+		 * If SO_LINGER has set a zero linger time, abort the
+		 * connection with a reset.
+		 */
+		if (connp->conn_linger && connp->conn_lingertime == 0) {
+			msg = "dccp_close, zero lingertime";
+			break;
+		}
+	}
+}
+
+/* ARGSUSED */
+void
+dccp_shutdown_output(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
+{
+	conn_t	*connp = (conn_t *)arg;
+	dccp_t	*dccp = connp->conn_dccp;
+
+	freemsg(mp);
+
+	if (dccp_xmit_end(dccp) != 0) {
+		/*
+		 * We were crossing FINs and got a reset from
+		 * the other side. Just ignore it.
+		 */
+		if (connp->conn_debug) {
+			(void) strlog(DCCP_MOD_ID, 0, 1,
+			    SL_ERROR|SL_TRACE,
+			    "dccp_shutdown_output() out of state %s",
+			    dccp_display(dccp, NULL, DISP_ADDR_AND_PORT));
+		}
+	}
+}
+
+#pragma inline(dccp_send_data)
+
+void
+dccp_send_data(dccp_t *dccp, mblk_t *mp)
+{
+	conn_t	*connp = dccp->dccp_connp;
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_sent_data");
+
+	/* XXX zcopy aware */
+
+	DTRACE_DCCP5(send, mblk_t *, NULL, ip_xmit_attr_t *, connp->conn_ixa,
+	    __dtrace_dccp_void_ip_t *, mp->b_rptr, dccp_t *, dccp,
+	    __dtrace_dccp_dccph_t *,
+	    &mp->b_rptr[connp->conn_ixa->ixa_ip_hdr_length]);
+
+	ASSERT(connp->conn_ixa->ixa_notify_cookie == connp->conn_tcp);
+	error = conn_ip_output(mp, connp->conn_ixa);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "conn_ip_output failed with code %d\n", error);
+	}
+}
+
+/*
+ * 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)
+{
+	netstack_t	*ns = ipst->ips_netstack;
+	dccp_stack_t	*dccps = ns->netstack_dccp;
+	ipsec_stack_t	*ipss = dccps->dccps_netstack->netstack_ipsec;
+	dccpha_t	*dccpha;
+	ipha_t		*ipha;
+	ip6_t		*ip6h;
+	uchar_t		*rptr;
+	uint32_t	seq_len;
+	uint_t		ip_hdr_len = ira->ira_ip_hdr_length;
+	boolean_t	policy_present;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_xmit_listeners_reset");
+
+	DCCP_STAT(dccps, dccp_no_listener);
+
+	if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
+		policy_present = ipss->ipsec_inbound_v4_policy_present;
+		ipha = (ipha_t *)mp->b_rptr;
+		ip6h = NULL;
+	} else {
+		policy_present = ipss->ipsec_inbound_v6_policy_present;
+		ipha = NULL;
+		ip6h = (ip6_t *)mp->b_rptr;
+	}
+
+	if (policy_present) {
+		mp = ipsec_check_global_policy(mp, (conn_t *)NULL, ipha, ip6h,
+		    ira, ns);
+		if (mp == NULL) {
+			return;
+		}
+	}
+
+	rptr = mp->b_rptr;
+
+	dccpha = (dccpha_t *)&rptr[ip_hdr_len];
+
+	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;
+	nmp_dccpha_ack->dha_ack_reserved = 0;
+
+	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];
+
+	if (connp != NULL) {
+		nmp_dccpha_reset->dha_reset_code =
+		    connp->conn_dccp->dccp_reset_code;
+	} else {
+		nmp_dccpha_reset->dha_reset_code =
+		    DCCP_RESET_CONNECTION_REFUSED;
+	}
+	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);
+}
+
+/* ARGSUSED2 */
+void
+dccp_send_synack(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
+{
+	conn_t		*econnp = (conn_t *)arg;
+	dccp_t		*dccp = econnp->conn_dccp;
+	ip_xmit_attr_t	*ixa = econnp->conn_ixa;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_send_synack");
+
+	/*
+	 * Guard against a RESET having blown it away while on the
+	 * squeue.
+	 */
+	if (dccp->dccp_state == DCCPS_CLOSED) {
+		freemsg(mp);
+		return;
+	}
+
+	ixa->ixa_pktlen = msgdsize(mp);
+	(void) conn_ip_output(mp, ixa);
+}
+
+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 = 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);
+}
+
+/*
+ * Generate a DCCP-Response packet.
+ */
+mblk_t *
+dccp_generate_response(conn_t *connp, mblk_t *mp)
+{
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ack_t	*dccpha_ack;
+	dccpha_srv_t	*dccpha_srv;
+	mblk_t		*mp1;
+	uint64_t	seq;
+	uint64_t	ack;
+	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;
+	uint_t		total_hdr_len;
+	uchar_t		*rptr;
+	dccp_t		*dccp = connp->conn_dccp;
+	void		*options;
+	size_t		opt_len;
+	int		error;
+
+	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;
+
+	seq = ntohs(ack_high) << 31;
+	seq |= ntohl(ack_low);
+
+	dccp->dccp_isr = seq;
+	dccp->dccp_gsr = seq;
+	dccp->dccp_swl = seq;
+	dccp->dccp_swh = seq;
+	dccp->dccp_gss++;
+
+	error = dccp_generate_options(dccp, &options, &opt_len);
+	if (error != 0) {
+		cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_options failed");
+	}
+	cmn_err(CE_NOTE, "generated options len: %d", (int) opt_len);
+
+
+	/*
+	 * conn_ht_iphc_len = ip_hdr_length (20) + ulp_hdr_length
+	 * (20) simple ip header (without vtag or options)
+	 */
+	total_hdr_len = len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len;
+	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(options, &mp1->b_rptr[len-opt_len], opt_len);
+        bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+        dccpha = (dccpha_t *)&rptr[ip_hdr_len];
+
+        dccpha->dha_type = DCCP_PKT_RESPONSE;
+        dccpha->dha_offset = 7 + (opt_len / 4);
+        dccpha->dha_x = 1;
+        dccpha->dha_ccval = 0;
+        dccpha->dha_cscov = 0;
+        dccpha->dha_reserved = 0;
+	dccpha->dha_res_seq = 0;
+	dccpha->dha_seq = htons(dccp->dccp_gss >> 32);;
+	dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t) + 4 + opt_len);
+
+
+	dccpha_ext = (dccpha_ext_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t)];
+	dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
+
+	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;
+	dccpha_ack->dha_ack_reserved = 0;
+
+	dccpha_srv = (dccpha_srv_t *)&mp1->b_rptr[ip_hdr_len + sizeof (dccpha_t) + sizeof (dccpha_ext_t) + sizeof (dccpha_ack_t)];
+	dccpha_srv->dha_srv_code = 0;
+
+	ixa->ixa_pktlen = total_hdr_len;
+
+	if (ixa->ixa_flags & IXAF_IS_IPV4) {
+		((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
+	} else {
+		ip6_t *ip6 = (ip6_t *)rptr;
+
+		ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
+	}
+
+	cmn_err(CE_NOTE, "IPHC LEN: %d", connp->conn_ht_iphc_len);
+	cmn_err(CE_NOTE, "TOTAL LEN: %d", total_hdr_len);
+
+	kmem_free(options, opt_len);
+
+	return (mp1);
+}
+
+/*
+ * Generate a request packet. Must use 48-bit sequence
+ * numbers.
+ */
+mblk_t *
+dccp_generate_request(conn_t *connp)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_srv_t	*dccpha_srv;
+	ip_xmit_attr_t	*ixa = connp->conn_ixa;
+	mblk_t		*mp;
+	uchar_t		*rptr;
+	uint_t		total_hdr_len;
+	uint_t		len;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_request");
+
+	total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_srv_t);
+	mp = allocb(total_hdr_len, BPRI_MED);
+	if (mp == NULL) {
+		cmn_err(CE_NOTE, "allocb failed");
+		return (NULL);
+	}
+
+	rptr = mp->b_rptr;
+	mp->b_wptr = &mp->b_rptr[total_hdr_len];
+
+	/* Copy in the template header */
+	bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+
+	len = ixa->ixa_ip_hdr_length;
+	dccpha = (dccpha_t *)&rptr[len];
+	dccpha->dha_type = DCCP_PKT_REQUEST;
+	dccpha->dha_offset = (sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_srv_t)) / 4;
+	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->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_srv_t));
+
+	/* Extended sequence number */
+	len += sizeof (dccpha_t);
+	dccpha_ext = (dccpha_ext_t *)&rptr[len];
+
+	/* Service number */
+	len += sizeof (dccpha_ext_t);
+	dccpha_srv = (dccpha_srv_t *)&rptr[len];
+	dccpha_srv->dha_srv_code = 0;
+
+	ixa->ixa_pktlen = total_hdr_len;
+
+	if (ixa->ixa_flags & IXAF_IS_IPV4) {
+		((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
+	} else {
+		ip6_t *ip6 = (ip6_t *)rptr;
+
+		ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
+	}
+
+	return (mp);
+}
+
+/*
+ * Close packet.
+ */
+mblk_t *
+dccp_generate_reset(conn_t *connp)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ack_t	*dccpha_ack;
+	dccpha_reset_t	*dccpha_reset;
+	ip_xmit_attr_t	*ixa = connp->conn_ixa;
+	mblk_t		*mp;
+	uint64_t	gss;
+	uchar_t		*rptr;
+	uint_t		total_hdr_len;
+	uint_t		len = ixa->ixa_ip_hdr_length;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_reset");
+
+	/* XXX */
+	dccp->dccp_gss++;
+
+	/*
+	 * Allocate a new DCCP reset message
+	 */
+	total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t);
+	mp = allocb(total_hdr_len, BPRI_MED);
+	if (mp == NULL) {
+		cmn_err(CE_NOTE, "allocb failed");
+		return(NULL);
+	}
+
+	rptr = mp->b_rptr;
+	mp->b_wptr = &mp->b_rptr[total_hdr_len];
+
+	bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+
+	len = ixa->ixa_ip_hdr_length;
+	dccpha = (dccpha_t *)&mp->b_rptr[len];
+	dccpha->dha_type = DCCP_PKT_RESET;
+	dccpha->dha_offset = 7;
+	dccpha->dha_x = 1;
+	dccpha->dha_ccval = 0;
+	dccpha->dha_cscov = 0;
+	dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_ack_t) + sizeof (dccpha_reset_t));
+	dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
+	dccpha->dha_res_seq = 0;
+
+	len += sizeof (dccpha_t);
+	dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
+	dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
+
+	/* Set ack */
+	len += sizeof (dccpha_ext_t);
+	dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
+	dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
+	dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
+	dccpha_ack->dha_ack_reserved = 0;
+
+	len += sizeof (dccpha_ack_t);
+	dccpha_reset = (dccpha_reset_t *)&mp->b_rptr[len];
+	dccpha_reset->dha_reset_code = dccp->dccp_reset_code;
+	dccpha_reset->dha_reset_data[0] = dccp->dccp_reset_data[0];
+	dccpha_reset->dha_reset_data[1] = dccp->dccp_reset_data[1];
+	dccpha_reset->dha_reset_data[2] = dccp->dccp_reset_data[2];
+
+	ixa->ixa_pktlen = total_hdr_len;
+
+	if (ixa->ixa_flags & IXAF_IS_IPV4) {
+		cmn_err(CE_NOTE, "setting ip len for ipv4: %d", total_hdr_len);
+		((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
+	} else {
+		ip6_t *ip6 = (ip6_t *)rptr;
+
+		ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
+	}
+
+	return (mp);
+}
+
+/*
+ * Acknowledgement packet.
+ */
+mblk_t *
+dccp_generate_ack(conn_t *connp)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ack_t	*dccpha_ack;
+	ip_xmit_attr_t	*ixa = connp->conn_ixa;
+	mblk_t		*mp;
+	uint64_t	gss;
+	uchar_t		*rptr;
+	uint_t		total_hdr_len;
+	uint_t		len = ixa->ixa_ip_hdr_length;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_ack");
+
+	/* XXX */
+	dccp->dccp_gss++;
+
+	/*
+	 * Allocate a new DCCP reset message
+	 */
+	total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_ack_t);
+	mp = allocb(total_hdr_len, BPRI_MED);
+	if (mp == NULL) {
+		cmn_err(CE_NOTE, "allocb failed");
+		return(NULL);
+	}
+
+	rptr = mp->b_rptr;
+	mp->b_wptr = &mp->b_rptr[total_hdr_len];
+
+	bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+
+	len = ixa->ixa_ip_hdr_length;
+	dccpha = (dccpha_t *)&mp->b_rptr[len];
+	dccpha->dha_type = DCCP_PKT_ACK;
+	dccpha->dha_offset = 6;
+	dccpha->dha_x = 1;
+	dccpha->dha_ccval = 0;
+	dccpha->dha_cscov = 0;
+	dccpha->dha_sum = htons(sizeof (dccpha_t) + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_ack_t));
+	dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
+	dccpha->dha_res_seq = 0;
+
+	len += sizeof (dccpha_t);
+	dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
+	dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
+
+	len += sizeof (dccpha_ext_t);
+	dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
+	dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
+	dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
+	dccpha_ack->dha_ack_reserved = 0;
+
+	ixa->ixa_pktlen = total_hdr_len;
+
+	if (ixa->ixa_flags & IXAF_IS_IPV4) {
+		((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
+	} else {
+		ip6_t *ip6 = (ip6_t *)rptr;
+
+		ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
+	}
+
+	return (mp);
+}
+
+/*
+ * Common to all packet generating functions.
+ */
+static mblk_t *
+dccp_generate_common(conn_t *connp, uint8_t packet_type,
+    uint_t total_hdr_len)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ack_t	*dccpha_ack;
+	ip_xmit_attr_t	*ixa = connp->conn_ixa;
+	mblk_t		*mp;
+	uchar_t		*rptr;
+	uint_t		len;
+	boolean_t	extended;
+
+	/*
+	 * Allocate a new DCCP reset message
+	 */
+	mp = allocb(total_hdr_len, BPRI_MED);
+	if (mp == NULL) {
+		return(NULL);
+	}
+
+	dccp->dccp_gss++;
+
+	rptr = mp->b_rptr;
+	mp->b_wptr = &mp->b_rptr[total_hdr_len];
+
+	bcopy(connp->conn_ht_iphc, rptr, connp->conn_ht_iphc_len);
+
+	/* Basic header */
+	len = ixa->ixa_ip_hdr_length;
+	dccpha = (dccpha_t *)&mp->b_rptr[len];
+	dccpha->dha_type = packet_type;
+	dccpha->dha_offset = 6;
+	dccpha->dha_x = 1;
+	dccpha->dha_ccval = 0;
+	dccpha->dha_cscov = 0;
+	dccpha->dha_sum = htons(total_hdr_len - len);
+	dccpha->dha_seq = htons(dccp->dccp_gss >> 32);
+	dccpha->dha_res_seq = 0;
+
+	/* Extended sequence number */
+	len += sizeof (dccpha_t);
+	dccpha_ext = (dccpha_ext_t *)&mp->b_rptr[len];
+	dccpha_ext->dha_ext_seq = htonl(dccp->dccp_gss & 0xffffffff);
+
+	/* Acknowledgement number */
+	len += sizeof (dccpha_ext_t);
+	dccpha_ack = (dccpha_ack_t *)&mp->b_rptr[len];
+	dccpha_ack->dha_ack_high = htons(dccp->dccp_gsr >> 32);
+	dccpha_ack->dha_ack_low = htonl(dccp->dccp_gsr & 0xffffffff);
+	dccpha_ack->dha_ack_reserved = 0;
+
+	ixa->ixa_pktlen = total_hdr_len;
+
+	if (ixa->ixa_flags & IXAF_IS_IPV4) {
+		((ipha_t *)rptr)->ipha_length = htons(total_hdr_len);
+	} else {
+		ip6_t *ip6 = (ip6_t *)rptr;
+
+		ip6->ip6_plen = htons(total_hdr_len - IPV6_HDR_LEN);
+	}
+
+	return (mp);
+}
+
+/*
+ * Acknowledgement packet.
+ */
+mblk_t *
+dccp_generate_sync(conn_t *connp)
+{
+	dccp_t		*dccp = connp->conn_dccp;
+	dccpha_t	*dccpha;
+	dccpha_ext_t	*dccpha_ext;
+	dccpha_ack_t	*dccpha_ack;
+	ip_xmit_attr_t	*ixa = connp->conn_ixa;
+	mblk_t		*mp;
+	uchar_t		*rptr;
+	uint_t		total_hdr_len;
+	uint_t		len = ixa->ixa_ip_hdr_length;
+
+	cmn_err(CE_NOTE, "dccp_output.c: dccp_generate_ack");
+
+	total_hdr_len = connp->conn_ht_iphc_len + sizeof (dccpha_ext_t) +
+	    sizeof (dccpha_ack_t);
+	mp = dccp_generate_common(connp, DCCP_PACKET_SYNC, total_hdr_len);
+	if (mp == NULL) {
+		cmn_err(CE_NOTE, "allocb failed");
+		return(NULL);
+	}
+
+	rptr = mp->b_rptr;
+	mp->b_wptr = &mp->b_rptr[total_hdr_len];
+
+	return (mp);
+}
