--- /dev/null	2012-08-18 10:36:57.000000000 +0000
+++ new/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dccp.c	2012-08-18 10:36:57.854154024 +0000
@@ -0,0 +1,433 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2012 David Hoeppner.  All rights reserved.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/dccp.h>
+#include "snoop.h"
+
+/*
+ * Snoop interpreter for DCCP (RFC4340)
+ *
+ */
+
+extern char *dlc_header;
+
+static char	*get_type(uint8_t);
+static void	print_dccpoptions_summary(uchar_t *, uchar_t *);
+static void	print_dccpoptions(uchar_t *, uchar_t *);
+
+static char *
+get_type(uint8_t type)
+{
+	switch (type) {
+	case 0:
+		return ("DCCP-Request");
+	case 1:
+		return ("DCCP-Response");
+	case 2:
+		return ("DCCP-Data");
+	case 3:
+		return ("DCCP-Ack");
+	case 4:
+		return ("DCCP-DataAck");
+	case 5:
+		return ("DCCP-CloseReq");
+	case 6:
+		return ("DCCP-Close");
+	case 7:
+		return ("DCCP-Reset");
+	case 8:
+		return ("DCCP-Sync");
+	case 9:
+		return ("DCCP-SyncAck");
+	case 10 ... 15:
+		return ("Reserved");
+
+	default:
+		return ("Unknown");
+	}
+}
+
+int
+interpret_dccp(int flags, struct dccphdr *dccp, int iplen, int fraglen)
+{
+	char		*data;
+	char		*line;
+	char		*endline;
+	uint64_t	seq;
+	uint64_t	ack;
+	int		hdrlen;
+	int		dccplen;
+	int		option_offset;
+	int		i;
+
+	hdrlen = dccp->dh_offset * 4;
+	data = (char *)dccp + hdrlen;
+	dccplen = iplen - hdrlen;
+	fraglen -= hdrlen;
+
+	if (fraglen < 0) {
+		return (fraglen + hdrlen);	/* Incomplete header */
+	}
+
+	if (fraglen > dccplen) {
+		fraglen = dccplen;
+	}
+
+	if (dccp->dh_x == 1) {
+		switch (dccp->dh_type) {
+		case 0:		/* DCCP-Request */
+			option_offset = 20;
+			break;
+		case 1:		/* DCCP-Response */
+			option_offset = 28;
+			break;
+		case 7:		/* DCCP-Reset */
+			option_offset = 28;
+			break;
+		case 8:		/* DCCP-Sync */
+		case 9:		/* DCCP-SyncAck */
+			option_offset = 24;
+			break;
+
+		default:
+			option_offset = 20;
+			break;
+		}
+
+		/* Sequence number */
+		seq = ntohs(dccp->dh_seq);
+		seq <<= 32;
+		seq += (uint32_t)dccp + sizeof (struct dccphdr);
+
+		ack = (uint32_t)(dccp + 16) & 0xffff;
+	} else {
+		switch (dccp->dh_type) {
+		case 0:		/* DCCP-Request */
+		case 1:		/* DCCP-Response */
+		case 7:		/* DCCP-Reset */
+		case 8:		/* DCCP-Sync */
+		case 9:		/* DCCP-SyncAck */
+			break;
+
+		default:
+			option_offset = 20;
+			break;
+		}
+
+		/* Sequence number */
+		seq = dccp->dh_res_seq << 16;
+		seq |= ntohs(dccp->dh_seq);
+	}
+
+	if (flags & F_SUM) {
+		line = get_sum_line();
+		endline = line + MAXLINE;
+
+		(void) snprintf(line, endline - line, "DCCP D=%d S=%d",
+		    ntohs(dccp->dh_dport), ntohs(dccp->dh_sport));
+		line += strlen(line);
+
+		(void) snprintf(line, endline - line, "CCval=%d CsCov=%d",
+		    dccp->dh_ccval, dccp->dh_cscov);
+
+		(void) snprintf(line, endline - line, " Seq=%u Len=%d",
+		    seq, dccplen);
+		line += strlen(line);
+
+		/*
+		 * All packets except DCCP-Request and DCCP-Data carry
+		 * an acknowledgement number.
+		 */
+		if (dccp->dh_type != 0 && dccp->dh_type != 2) {
+			(void) snprintf(line, endline - line, " Ack=%u",
+			    seq, dccplen);
+		}
+		line += strlen(line);
+
+		print_dccpoptions_summary((uchar_t *)dccp + option_offset,
+		    (uchar_t *)dccp + dccp->dh_offset * 4);
+	}
+
+
+	if (flags & F_DTAIL) {
+		show_header("DCCP:  ", "DCCP Header", dccplen);
+		show_space();
+
+		(void) sprintf(get_line((char *)(uintptr_t)dccp->dh_sport -
+		    dlc_header, 2), "Source port = %d",
+		    ntohs(dccp->dh_sport));
+
+		(void) sprintf(get_line((char *)(uintptr_t)dccp->dh_dport -
+		    dlc_header, 2), "Destination port = %d",
+		    ntohs(dccp->dh_dport));
+
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_offset -
+		    dlc_header) + 4, 1), "Data offset = %d bytes",
+		    dccp->dh_offset * 4);
+
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_ccval -
+		    dlc_header) + 4, 1), "CCVal = %d",
+		    dccp->dh_ccval);
+
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_cscov -
+		    dlc_header) + 4, 1), "Checksum coverage (CsCov) = %d",
+		    dccp->dh_cscov);
+
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_sum -
+		    dlc_header) + 4, 1), "Checksum = 0x%04x",
+		    ntohs(dccp->dh_sum));
+
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_type -
+		    dlc_header) + 4, 1), "Type = %d (%s)",
+		    dccp->dh_type, get_type(dccp->dh_type));
+
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_x -
+		    dlc_header) + 4, 1), "Extended sequence numbers = %d",
+		    dccp->dh_x);
+
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_seq -
+		    dlc_header) + 4, 1), "Sequence number = %d",
+		    seq);
+
+		/*
+		 * All packets except DCCP-Request and DCCP-Data carry
+		 * an acknowledgement number.
+		 */
+		if (dccp->dh_type != 0 && dccp->dh_type != 2) {
+		(void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_seq -
+		    dlc_header) + 4, 1), "Acknowledgement number = %d",
+		    seq);
+		}
+
+		print_dccpoptions((uchar_t *)dccp + option_offset,
+		    (uchar_t *)dccp + dccp->dh_offset * 4);
+
+		show_space();
+	}
+
+	return (dccplen);
+}
+
+static void
+print_dccpoptions_summary(uchar_t *up, uchar_t *end)
+{
+	uchar_t		*value;
+	uint8_t		option_type;
+	uint8_t		option_length;
+	int		len;
+	boolean_t	mandatory = B_FALSE;
+
+	while (up != end) {
+		option_length = 0;
+		option_type = *up++;
+
+		/*
+		 * Is this a variable length option?
+		 */
+		if (option_type > 31) {
+			option_length = *up++;
+			option_length -= 2;
+			value = up;
+
+			up += option_length;
+		}
+		switch (option_type) {
+		case 0:		/* Padding */
+			break;
+		case 1:		/* Mandatory */
+			mandatory = B_TRUE;
+			break;
+		case 2:		/* Slow receiver */
+			break;
+		case 3 ... 31:	/* Reserved */
+			break;
+		case 32:	/* Change L */
+			break;
+		case 33:	/* Confirm L */
+			break;
+		case 34:	/* Change R */
+			break;
+		case 35:	/* Confirm R */
+			break;
+		case 36:	/* Init cookie */
+			break;
+		case 37:	/* NDP count */
+			break;
+		case 38:	/* Ack Vector 0 */
+			break;
+		case 39:	/* Ack vector 1 */
+			break;
+		case 40:	/* Data dropped */
+			break;
+		case 41:	/* Timestamp */
+			break;
+		case 42:	/* Timestamp echo */
+			break;
+		case 43:	/* Elapsed time */
+			break;
+		case 44:	/* Data checksum */
+			break;
+
+		default:
+			break;
+		}
+
+		if (option_type != 1) {
+			mandatory = B_FALSE;
+		}
+	}
+}
+
+static void
+print_dccpoptions(uchar_t *up, uchar_t *end)
+{
+	uchar_t		*value;
+	uint8_t		option_type;
+	uint8_t		option_length;
+	int		len;
+	boolean_t	mandatory = B_FALSE;
+
+	if (up == end) {
+		(void) sprintf(get_line((char *)&up - dlc_header, 1),
+		     "No options");
+		return;
+	}
+
+	(void) sprintf(get_line((char *)&up - dlc_header, 1),
+	    "Options: (%d bytes)", (int)(end - up));
+
+	while (up != end) {
+		option_length = 0;
+		option_type = *up++;
+
+		/*
+		 * Is this a variable length option?
+		 */
+		if (option_type > 31) {
+			option_length = *up++;
+			option_length -= 2;
+			value = up;
+
+			up += option_length;
+		}
+
+		switch (option_type) {
+		case 0:		/* Padding */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Padding");
+			break;
+		case 1:		/* Mandatory */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Mandatory");
+			mandatory = B_TRUE;
+			break;
+		case 2:		/* Slow receiver */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Slow receiver");
+			break;
+		case 3 ... 31:	/* Reserved */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Reserved");
+			break;
+		case 32:	/* Change L */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Change L");
+			break;
+		case 33:	/* Confirm L */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Confirm L");
+			break;
+		case 34:	/* Change R */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Change R");
+			break;
+		case 35:	/* Confirm R */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Confirm R");
+			break;
+		case 36:	/* Init cookie */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Init cookie");
+			break;
+		case 37:	/* NDP count */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "NDP count");
+			break;
+		case 38:	/* Ack vector 0 */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Ack vector 0");
+			break;
+		case 39:	/* Ack vector 1 */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Ack vector 1");
+			break;
+		case 40:	/* Data dropped */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Data dropped");
+			break;
+		case 41:	/* Timestamp */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Timestamp");
+			break;
+		case 42:	/* Timestamp echo */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "TImestamp echo");
+			break;
+		case 43:	/* Elapsed time */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Elapsed time");
+			break;
+		case 44:	/* Data checksum */
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Data checksum");
+			break;
+
+		default:
+			(void) sprintf(get_line(((char *)(uintptr_t)up -
+			    dlc_header) + 4, 1), "Unknown");
+			break;
+		}
+
+		if (option_type != 1) {
+			mandatory = B_FALSE;
+		}
+	}
+}
