Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-dev: [Wireshark-dev] [PATCH 1/1][DCCP Dissector]: Feature-Negotiation options, update

From: Gerrit Renker <gerrit@xxxxxxxxxxxxxx>
Date: Tue, 25 Sep 2007 12:40:57 +0100
This is an update for the DCCP dissector and has previously been sent to
the DCCP dissector maintainer, Francesco Fondelli, (CC:ed), who supplied
the Acked-by.
I have been using it with profit for several weeks.

This patch provides the following extensions:
 * type-dependent decoding of feature-negotiation options (NN and SP types of options,
   NN is a 1..6 byte value in network-byte-order, SP is always a list of unsigned char)
 * decoding for CCID3 Send Loss Event Rate feature
 * some pretty-printing of options
 
 * decoding of CCID3-specific options
	- Loss Event Rate (receiver report)
	- Receive Rate (also reported by receiver)

 * there was a change in the spec - the NDP count at sometime `grew' from 3 to 6 bytes
   (it was the same in the kernel). I have updated the data type from uint32 to uint64

 * utility function to decode from network-byte-order into host byte order with variable length


Signed-off-by: Gerrit Renker <gerrit@xxxxxxxxxxxxxx>
Acked-by:  Francesco Fondelli <francesco.fondelli@xxxxxxxxx>

[patch as attachment, not inline]
Index: epan/dissectors/packet-dcp.c
===================================================================
--- epan/dissectors/packet-dcp.c	(revision 22858)
+++ epan/dissectors/packet-dcp.c	(working copy)
@@ -118,6 +118,14 @@
         {0, NULL}
 };
 
+static const value_string dcp_feature_options_vals[] = {
+        {0x20, "Change L"},
+	{0x21, "Confirm L"},
+	{0x22, "Change R"},
+	{0x23, "Confirm R"},
+        {0, NULL}
+};
+
 static const value_string dcp_feature_numbers_vals[] = {
         {0x01, "CCID"},
         {0x02, "Allow Short Seqnos"},
@@ -128,6 +136,7 @@
         {0x07, "Send NDP Count"},
 	{0x08, "Minimum Checksum Coverage"},
 	{0x09, "Check Data Checksum"},
+	{0xC0, "Send Loss Event Rate"},		/* CCID3, RFC 4342, 8.5 */
         {0, NULL}
 };
 
@@ -263,7 +272,84 @@
 	call_dissector(data_handle, next_tvb, pinfo, tree);
 }
 
+/*
+ *	Auxiliary functions to dissect DCCP options
+ */
+/* decode a variable-length number of nbytes starting at offset. Based on a concept by Arnaldo de Melo */
+static guint64 tvb_get_ntoh_var(tvbuff_t *tvb, gint offset, guint8 nbytes)
+{
+	const guint8* ptr;
+	guint64 value = 0;
 
+        ptr = tvb_get_ptr(tvb, offset, nbytes);
+	if (nbytes > 5)
+                value += ((guint64)*ptr++) << 40;
+	if (nbytes > 4)
+                value += ((guint64)*ptr++) << 32;
+	if (nbytes > 3)
+                value += ((guint64)*ptr++) << 24;
+	if (nbytes > 2)
+                value += ((guint64)*ptr++) << 16;
+	if (nbytes > 1)
+                value += ((guint64)*ptr++) << 8;
+	if (nbytes > 0)
+                value += *ptr;
+
+        return value;
+}
+
+static void dissect_feature_options(proto_tree *dcp_options_tree, tvbuff_t *tvb, int offset, guint8 option_len, 
+				    guint8 option_type)
+{
+	guint8 feature_number = tvb_get_guint8(tvb, offset + 2);
+	proto_item *dcp_item;
+	int i;
+	
+	proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
+
+	dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "%s(",
+				       val_to_str(option_type, dcp_feature_options_vals, "Unknown Type"));
+		
+	/* decode the feature according to whether it is server-priority (list) or NN (single number) */
+	switch (feature_number) {
+	/*		Server Priority features (RFC 4340, 6.3.1)		*/
+	case 1:			/* Congestion Control ID (CCID); fall through	*/
+	case 2:			/* Allow Short Seqnos; fall through		*/
+	case 4:			/* ECN Incapable; fall through			*/
+	case 6:			/* Send Ack Vector; fall through		*/
+	case 7:			/* Send NDP Count; fall through			*/
+	case 8:			/* Minimum Checksum Coverage; fall through	*/
+	case 9:			/* Check Data Checksum; fall through		*/
+	case 192:		/* Send Loss Event Rate, RFC 4342, section 8.4	*/
+		proto_item_append_text(dcp_item, "%s", 
+				       val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
+		for (i = 0; i < option_len - 3; i++) 
+			proto_item_append_text(dcp_item, "%s %d", i? "," : "", tvb_get_guint8(tvb, offset + 3 + i));
+		break;
+	/*	 Non-negotiable features (RFC 4340, 6.3.2)	 */
+	case 3:			/* Sequence Window; fall through */
+	case 5: 		/* Ack Ratio			 */
+		proto_item_append_text(dcp_item, "%s", 
+				       val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
+
+		if (option_len > 3)	/* could be empty Confirm */
+			proto_item_append_text(dcp_item, " %llu", tvb_get_ntoh_var(tvb, offset + 3, option_len - 3));
+		break;
+	/* Reserved, specific, or unknown features */		
+	case 0:			/* fall through */
+	case 10 ... 127:
+		proto_item_append_text(dcp_item, "Reserved feature number %d", feature_number);
+		break;
+	case 193 ... 255:
+		proto_item_append_text(dcp_item, "CCID-specific feature number %d", feature_number);
+		break;
+	default:
+		proto_item_append_text(dcp_item, "Unknown feature number %d", feature_number);
+		break;
+	}
+	proto_item_append_text(dcp_item, ")");
+}
+
 /*
  * This function dissects DCCP options
  */
@@ -274,9 +360,9 @@
 	/* if here I'm sure there is at least offset_end - offset_start bytes in tvb and it should be options */
 	int offset=offset_start;
 	guint8 option_type = 0;
-	guint8 option_len = 0;
-	guint8 feature_number = 0;
+	guint8 option_len  = 0;
 	int i;
+	guint32 p;
 	proto_item *dcp_item = NULL;
 
 	while( offset < offset_end ) {
@@ -327,106 +413,10 @@
 			proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Slow Receiver");
 			break;
 
-		case 32:
-			feature_number = tvb_get_guint8(tvb, offset + 2);
-			proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
-
-			if( (feature_number < 10) && (feature_number!=0) ) {
-				dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							       "Change L(%s",
-							       val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
-				for (i = 0; i < option_len - 3; i++) {
-					if(i==0)
-						proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
-					else
-						proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
-				}
-				proto_item_append_text(dcp_item, ")");
-			} else {
-				if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Change L(Reserved feature number)");
-				else
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Change L(CCID-specific features)");
-			}
+		case 32 ... 35:
+			dissect_feature_options(dcp_options_tree, tvb, offset, option_len, option_type);
 			break;
 
-		case 33:
-			feature_number = tvb_get_guint8(tvb, offset + 2);
-			proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
-
-			if( (feature_number < 10) && (feature_number!=0) ) {
-				dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							       "Confirm L(%s",
-							       val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
-				for (i = 0; i < option_len - 3; i++) {
-					if(i==0)
-						proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
-					else
-						proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
-				}
-				proto_item_append_text(dcp_item, ")");
-			} else {
-				if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Confirm L(Reserved feature number)");
-				else
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Confirm L(CCID-specific features)");
-			}
-			break;
-
-		case 34:
-			feature_number = tvb_get_guint8(tvb, offset + 2);
-			proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
-
-			if( (feature_number < 10) && (feature_number!=0) ) {
-				dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							       "Change R(%s",
-							       val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
-				for (i = 0; i < option_len - 3; i++) {
-					if(i==0)
-						proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
-					else
-						proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
-				}
-				proto_item_append_text(dcp_item, ")");
-			} else {
-				if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Change R(Reserved feature number)");
-				else
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Change R(CCID-specific features)");
-			}
-			break;
-
-		case 35:
-			feature_number = tvb_get_guint8(tvb, offset + 2);
-			proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
-
-			if( (feature_number < 10) && (feature_number!=0) ) {
-				dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							       "Confirm R(%s",
-							       val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
-				for (i = 0; i < option_len - 3; i++) {
-					if(i==0)
-						proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
-					else
-						proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
-				}
-				proto_item_append_text(dcp_item, ")");
-			} else {
-				if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Confirm R(Reserved feature number)");
-				else
-					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
-							    "Confirm R(CCID-specific features)");
-			}
-			break;
-
 		case 36:
 			dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Init Cookie(");
 			for (i = 0; i < option_len - 2; i++) {
@@ -439,51 +429,30 @@
 			break;
 
 		case 37:
-			if(option_len==3)
-				proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 1,
-						    tvb_get_guint8(tvb, offset + 2));
-			else if (option_len==4)
-				proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 2,
-						    tvb_get_ntohs(tvb, offset + 2));
-			else if (option_len==5)
-				proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 3,
-						    tvb_get_ntoh24(tvb, offset + 2));
+			if (option_len > 8)
+				proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count too long (max 6 bytes)");
 			else
-				proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count too long (max 3 bytes)");
-
+				proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count: %llu",
+						    tvb_get_ntoh_var(tvb, offset + 2, option_len - 2));
 			break;
 
 		case 38:
-			dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector0(");
-			for (i = 0; i < option_len - 2; i++) {
-				if(i==0)
-					proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
-				else
-					proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
-			}
-			proto_item_append_text(dcp_item, ")");
+			dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector [Nonce 0]:");
+			for (i = 0; i < option_len - 2; i++) 
+				proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
 			break;
 
 		case 39:
-			dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector1(");
-			for (i = 0; i < option_len - 2; i++) {
-				if(i==0)
-					proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
-				else
-					proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
-			}
+			dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector [Nonce 1]:");
+			for (i = 0; i < option_len - 2; i++)
+				proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
 			proto_item_append_text(dcp_item, ")");
 			break;
 
 		case 40:
-			dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Data Dropped(");
-			for (i = 0; i < option_len - 2; i++) {
-				if(i==0)
-					proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
-				else
-					proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
-			}
-			proto_item_append_text(dcp_item, ")");
+			dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Data Dropped:");
+			for (i = 0; i < option_len - 2; i++) 
+				proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
 			break;
 
 		case 41:
@@ -533,7 +502,28 @@
 			} else
 				proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Data checksum length");
 			break;
-
+		case 192:	/* RFC 4342, 8.5 */
+			if(option_len == 6) {
+				p = tvb_get_ntohl(tvb, offset + 2);
+				/* According to the comment in section 8.5 of RFC 4342, 0xffffffff can mean zero */
+				if (p == 0xFFFFFFFF)
+					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: 0 (or max)");
+				else
+					proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: %u", p);
+			} else
+				proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong CCID3 Loss Event Rate length");
+			break;
+		case 193:	/* RFC 4342, 8.6 */
+			proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Intervals");
+				/* FIXME: not implemented and apparently not used by any implementation so far */
+			break;
+		case 194:	/* RFC 4342, 8.3 */
+			if(option_len == 6)
+				proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Receive Rate: %u bytes/sec",
+						    tvb_get_ntohl(tvb, offset + 2));
+			else
+				proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong CCID3 Receive Rate length");
+			break;
 		default :
 			if(((option_type >= 45) && (option_type <= 127)) ||
 			   ((option_type >=  3) && (option_type <=  31))) {
@@ -553,7 +543,7 @@
 		} /* end switch() */
 
 		offset+=option_len; /* Skip over the dissected option */
-
+		
 	} /* end while() */
 }
 /* compute DCCP checksum coverage according to RFC 4340, section 9 */
@@ -1082,7 +1072,7 @@
 		  "", HFILL }},
 
 		{ &hf_dcp_ndp_count,
-		{ "NDP Count",   "dcp.ndp_count", FT_UINT32, BASE_DEC, NULL, 0x0,
+		{ "NDP Count",   "dcp.ndp_count", FT_UINT64, BASE_DEC, NULL, 0x0,
 		  "", HFILL }},
 
 		{ &hf_dcp_timestamp,