--- /dev/null	2012-08-18 10:37:10.000000000 +0000
+++ new/usr/src/uts/common/inet/dccp/dccp_options.c	2012-08-18 10:37:10.530253402 +0000
@@ -0,0 +1,336 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012 David Hoeppner. All rights reserved.
+ */
+
+#include <sys/types.h> 
+#include <sys/stream.h> 
+#include <sys/debug.h> 
+#include <sys/cmn_err.h>
+
+#include <inet/dccp_impl.h>
+#include <inet/dccp_stack.h>
+
+/*
+ * This file contains functions to parse and process DCCP options.
+ */
+
+
+/*
+ * Parse the options in a DCCP header.
+ */
+int
+dccp_parse_options(dccp_t *dccp, dccpha_t *dccpha)
+{
+	uchar_t		*end;
+	uchar_t		*up;
+	uint8_t		dccp_type;
+	uint32_t	option_value;
+	uint8_t		option_type;
+	uint8_t		option_length;
+	int		len;
+	int		i;
+	uchar_t		*value;
+	boolean_t	mandatory = B_FALSE;
+	int		error;
+
+	cmn_err(CE_NOTE, "dccp_features.c: dccp_parse_options");
+
+	dccp_type = dccpha->dha_type;
+
+	up = (uchar_t *)dccpha;
+	end = up + DCCP_HDR_LENGTH(dccpha);
+	up += 20;
+
+	while (up != end) {
+		option_length = 0;
+		option_type = *up++;
+
+		if (option_type > 31) {
+			if (up == end) {
+				goto length_error;
+			}
+
+			option_length = *up++;
+			if (option_length < 2) {
+				goto length_error;
+			}
+
+			option_length -= 2;
+			value = up;
+
+			up += option_length;
+
+			/* Ignore options with greater length then header */
+			if (up > end) {
+				goto length_error;
+			}
+		} else {
+			value = up;
+		}
+
+		/* Single byte unknow option */
+		if (option_type >= 3 && option_type <=31) {
+			if (mandatory) {
+				error = DCCP_RESET_MANDATORY_ERROR;
+			} else {
+				error = DCCP_RESET_OPTION_ERROR;
+			}
+
+			dccp->dccp_reset_code = error;
+			/*
+			 * this should be correct:
+			 * dccp->dccp_reset_data[0] = option_type;
+			 * dccp->dccp_reset_data[1] = value[0];
+			 *
+			 * error in the test suit?
+			 */
+			dccp->dccp_reset_data[0] = value[0];
+			dccp->dccp_reset_data[1] = 0;
+			dccp->dccp_reset_data[2] = 0;
+
+			return (-1);
+		}
+
+		if (option_type >= 45 && option_type <=127)
+			break;
+
+
+		switch (option_type) {
+		case DCCP_OPTION_PADDING:
+			cmn_err(CE_NOTE, "PADDING");
+			break;
+		case DCCP_OPTION_MANDATORY:
+			cmn_err(CE_NOTE, "MANDATORY");
+			if (mandatory)
+				goto option_error;
+
+			if (dccp_type != DCCP_PKT_DATA)
+				mandatory = B_TRUE;
+			break;
+		case DCCP_OPTION_SLOW_RECEIVER:
+			cmn_err(CE_NOTE, "SLOW RECEIVER");
+			break;
+		case DCCP_OPTION_CHANGE_L:
+		case DCCP_OPTION_CONFIRM_L:
+		case DCCP_OPTION_CHANGE_R:
+		case DCCP_OPTION_CONFIRM_R:
+			if (dccp_type == DCCP_PACKET_DATA)
+				break;
+
+			if (option_length == 0)
+				goto option_error;
+
+			error = dccp_parse_feature(dccp, option_type, option_length,
+			    value, mandatory);
+			if (error != 0)
+				goto feature_error;
+
+			break;
+		case DCCP_OPTION_INIT_COOKIE:
+			cmn_err(CE_NOTE, "INIT COOKIE");
+			break;
+		case DCCP_OPTION_NDP_COUNT:
+			cmn_err(CE_NOTE, "NDP COUNT");
+			if (option_length > 6)
+				goto option_error;
+			break;
+		case DCCP_OPTION_ACK_VECTOR_1:
+			cmn_err(CE_NOTE, "ACK VECTOR 1");
+			break;
+		case DCCP_OPTION_ACK_VECTOR_2:
+			cmn_err(CE_NOTE, "ACK VECTOR 2");
+			break;
+		case DCCP_OPTION_DATA_DROPPED:
+			cmn_err(CE_NOTE, "DATA DROPPED");
+			break;
+		case DCCP_OPTION_TIMESTAMP:
+			cmn_err(CE_NOTE, "TIMESTAMP");
+			if (option_length != 4)
+				goto option_error;
+
+			option_value = BE32_TO_U32(value);
+			if (option_value == 0) {
+				cmn_err(CE_NOTE, "Zero timestamp");
+				break;
+			}
+
+			dccp->dccp_timestamp_echo = ntohs(option_value);
+			dccp->dccp_timestamp = TICK_TO_MSEC(LBOLT_FASTPATH);
+			break;
+		case DCCP_OPTION_TIMESTAMP_ECHO:
+			cmn_err(CE_NOTE, "TIMESTAMP ECHO");
+			if (option_length != 4 && option_length != 6 &&
+			    option_length != 8) {
+				goto option_error;
+			}
+
+			option_value = BE32_TO_U32(value);
+
+			option_length -= 4;
+			break;
+		case DCCP_OPTION_ELAPSED_TIME:
+			cmn_err(CE_NOTE, "ELAPSES TIME");
+			switch (option_length) {
+			case 2:
+				break;
+			case 4:
+				break;
+			default:
+				goto option_error;
+			}
+			break;
+		case DCCP_OPTION_DATA_CHECKSUM:
+			cmn_err(CE_NOTE, "DATA CHECKSUM");
+			break;
+
+		default:
+			cmn_err(CE_NOTE, "unknow option");
+			break;
+		}
+
+		if (option_type != DCCP_OPTION_MANDATORY) {
+			mandatory = B_FALSE;
+		}
+	}
+
+	if (mandatory)
+		goto option_error;
+
+length_error:
+	return (0);
+
+option_error:
+	if (mandatory) {
+		error = DCCP_RESET_MANDATORY_ERROR;
+	} else {
+		error = DCCP_RESET_OPTION_ERROR;
+	}
+
+	cmn_err(CE_NOTE, "setting error code");
+
+feature_error:
+	dccp->dccp_reset_code = error;
+	dccp->dccp_reset_data[0] = option_type;
+	dccp->dccp_reset_data[1] = option_length > 0 ? value[0] : 0;
+	dccp->dccp_reset_data[2] = option_length > 1 ? value[1] : 0;
+
+	return (-1);
+}
+
+int
+dccp_process_options(dccp_t *dccp, dccpha_t *dccpha)
+{
+	int	error;
+
+	cmn_err(CE_NOTE, "dccp_features.c: dccp_process_features");
+
+	error = dccp_parse_options(dccp, dccpha);
+
+	return (error);
+}
+
+int
+dccp_generate_options(dccp_t *dccp, void **opt, size_t *opt_len)
+{
+	dccp_feature_t	*feature = NULL;
+	uint8_t		buf[1024];	/* XXX */
+	uint8_t		option_type;
+	uint_t		len = 0;
+	uint_t		total_len = 0;
+	void		*options = NULL;
+	int		rest;
+
+	cmn_err(CE_NOTE, "dccp_features.c: dccp_generate_options");
+
+	for (feature = list_head(&dccp->dccp_features); feature;
+	    feature = list_next(&dccp->dccp_features, feature)) {
+		if (feature->df_option == DCCP_OPTION_CHANGE_L) {
+			option_type = DCCP_OPTION_CONFIRM_R;
+		} else {
+			option_type = DCCP_OPTION_CONFIRM_L;
+		}
+/*
+		if (feature->df_mandatory == B_TRUE) {
+			buf[len] = DCCP_OPTION_MANDATORY;
+			len++;
+		}
+*/
+		if (feature->df_type == DCCP_FEATURE_CCID) {
+			cmn_err(CE_NOTE, "FOUND DCCP_FEATURE_CCID");
+
+			buf[len] = option_type;
+			len++;
+			buf[len] = 4;
+			len++;
+			buf[len] = DCCP_FEATURE_CCID;
+			len++;
+			buf[len] = 2;
+			len++;
+		}
+
+		if (feature->df_type == DCCP_FEATURE_ALLOW_SHORT_SEQNOS) {
+			buf[len] = option_type;
+			len++;
+			buf[len] = 4;
+			len++;
+			buf[len] = feature->df_type;
+			len++;
+			buf[len] = 0;
+			len++;
+		}
+
+		if (feature->df_type == DCCP_FEATURE_ECN_INCAPABLE) {
+			buf[len] = option_type;
+			len++;
+			buf[len] = 4;
+			len++;
+			buf[len] = feature->df_type;
+			len++;
+			buf[len] = 1;
+			len++;
+		}
+	}
+
+	if (dccp->dccp_timestamp_echo != 0) {
+		uint32_t	elapsed;
+		int		elapsed_length;
+		clock_t		now;
+
+		buf[len] = DCCP_OPTION_TIMESTAMP_ECHO;
+		len++;
+		buf[len] = 10;
+		len++;
+
+		now = TICK_TO_MSEC(LBOLT_FASTPATH);
+		elapsed =  now - dccp->dccp_timestamp;
+
+
+		dccp->dccp_timestamp_echo = 0;
+	}
+
+	if (len != 0) {
+		total_len = ((len + (4 - 1)) / 4) * 4;
+		options = kmem_zalloc(total_len, KM_SLEEP);
+		if (options == NULL) {
+			cmn_err(CE_NOTE, "kmem_zalloc failed");
+			return (ENOMEM);
+		}
+		memcpy(options, buf, len);
+	}
+
+	*opt = options;
+	*opt_len = len;
+
+	return (0);
+}
