2 * Routines for Datagram Congestion Control Protocol, "DCCP" dissection:
3 * it should be conformance to draft-ietf-dccp-spec-11.txt
7 * Francesco Fondelli <francesco dot fondelli, gmail dot com>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * Copied from packet-udp.c
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 * Nov 13, 2006: makes checksum computation dependent
36 * upon the header CsCov field (cf. RFC 4340, 5.1)
39 * Nov 13, 2006: removes the case where checksums are zero
40 * (unlike UDP/packet-udp, from which the code stems,
41 * zero checksums are illegal in DCCP (as in TCP))
44 * Jan 29, 2007: updates the offsets of the timestamps to be
45 * compliant to (cf. RFC 4342, sec. 13).
58 #include <epan/packet.h>
59 #include <epan/addr_resolv.h>
60 #include <epan/ipproto.h>
61 #include <epan/in_cksum.h>
62 #include <epan/prefs.h>
63 #include <epan/emem.h>
65 #include "packet-dccp.h"
67 #include "packet-ip.h"
68 #include <epan/conversation.h>
71 /* Some definitions and the dissect_options() logic have been taken from Arnaldo Carvalho de Melo's DCCP implementation, thanks! */
73 #define DCCP_HDR_LEN 16 /* base DCCP header length, with 48 bits seqnos */
74 #define DCCP_HDR_LEN_MIN 12 /* , with 24 bits seqnum */
75 #define DCCP_HDR_PKT_TYPES_LEN_MAX 12 /* max per packet type extra header length */
76 #define DCCP_OPT_LEN_MAX 1008
77 #define DCCP_HDR_LEN_MAX (DCCP_HDR_LEN + DCCP_HDR_PKT_TYPES_LEN_MAX + DCCP_OPT_LEN_MAX)
80 static const value_string dccp_packet_type_vals[] = {
100 static const value_string dccp_reset_code_vals[] = {
101 {0x00, "Unspecified"},
104 {0x03, "No Connection"},
105 {0x04, "Packet Error"},
106 {0x05, "Option Error"},
107 {0x06, "Mandatory Error"},
108 {0x07, "Connection Refused"},
109 {0x08, "Bad Service Code"},
111 {0x0A, "Bad Init Cookie"},
112 {0x0B, "Aggression Penalty"},
117 static const value_string dccp_feature_options_vals[] = {
125 static const value_string dccp_feature_numbers_vals[] = {
127 {0x02, "Allow Short Seqnos"},
128 {0x03, "Sequence Window"},
129 {0x04, "ECN Incapable"},
131 {0x06, "Send Ack Vector"},
132 {0x07, "Send NDP Count"},
133 {0x08, "Minimum Checksum Coverage"},
134 {0x09, "Check Data Checksum"},
135 {0xC0, "Send Loss Event Rate"}, /* CCID3, RFC 4342, 8.5 */
141 #define DBG(str, args...) do {\
148 fprintf(stdout, str, ## args); \
152 #define DBG1(format, arg1)
153 #define DBG2(format, arg1, arg2)
157 static int proto_dccp = -1;
158 static int dccp_tap = -1;
160 static int hf_dccp_srcport = -1;
161 static int hf_dccp_dstport = -1;
162 static int hf_dccp_port = -1;
163 static int hf_dccp_data_offset = -1;
164 static int hf_dccp_ccval = -1;
165 static int hf_dccp_cscov = -1;
166 static int hf_dccp_checksum = -1;
167 static int hf_dccp_checksum_bad = -1;
168 static int hf_dccp_res1 = -1;
169 static int hf_dccp_type = -1;
170 static int hf_dccp_x = -1;
171 static int hf_dccp_res2 = -1;
172 static int hf_dccp_seq = -1;
174 static int hf_dccp_ack_res = -1;
175 static int hf_dccp_ack = -1;
177 static int hf_dccp_service_code = -1;
178 static int hf_dccp_reset_code = -1;
179 static int hf_dccp_data1 = -1;
180 static int hf_dccp_data2 = -1;
181 static int hf_dccp_data3 = -1;
183 static int hf_dccp_options = -1;
184 static int hf_dccp_option_type = -1;
185 static int hf_dccp_feature_number = -1;
186 static int hf_dccp_ndp_count = -1;
187 static int hf_dccp_timestamp = -1;
188 static int hf_dccp_timestamp_echo = -1;
189 static int hf_dccp_elapsed_time = -1;
190 static int hf_dccp_data_checksum = -1;
192 static int hf_dccp_malformed = -1;
194 static gint ett_dccp = -1;
195 static gint ett_dccp_options = -1;
197 static dissector_table_t dccp_subdissector_table;
198 static heur_dissector_list_t heur_subdissector_list;
199 static dissector_handle_t data_handle;
202 static gboolean dccp_summary_in_tree = TRUE;
203 static gboolean try_heuristic_first = FALSE;
204 static gboolean dccp_check_checksum = TRUE;
208 decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int sport, int dport)
211 int low_port, high_port;
213 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
215 /* determine if this packet is part of a conversation and call dissector */
216 /* for the conversation if available */
218 if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_DCCP, sport, dport, next_tvb, pinfo, tree)) {
222 if (try_heuristic_first) {
223 /* do lookup with the heuristic subdissector table */
224 if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {
229 /* Do lookups with the subdissector table.
230 We try the port number with the lower value first, followed by the
231 port number with the higher value. This means that, for packets
232 where a dissector is registered for *both* port numbers:
234 1) we pick the same dissector for traffic going in both directions;
236 2) we prefer the port number that's more likely to be the right
237 one (as that prefers well-known ports to reserved ports);
239 although there is, of course, no guarantee that any such strategy
240 will always pick the right port number.
241 XXX - we ignore port numbers of 0, as some dissectors use a port
242 number of 0 to disable the port. */
252 dissector_try_port(dccp_subdissector_table, low_port, next_tvb, pinfo, tree)) {
255 if (high_port != 0 &&
256 dissector_try_port(dccp_subdissector_table, high_port, next_tvb, pinfo, tree)) {
260 if (!try_heuristic_first) {
261 /* do lookup with the heuristic subdissector table */
262 if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {
267 /* Oh, well, we don't know this; dissect it as data. */
268 call_dissector(data_handle, next_tvb, pinfo, tree);
272 * Auxiliary functions to dissect DCCP options
274 /* decode a variable-length number of nbytes starting at offset. Based on a concept by Arnaldo de Melo */
275 static guint64 tvb_get_ntoh_var(tvbuff_t *tvb, gint offset, guint nbytes)
280 ptr = tvb_get_ptr(tvb, offset, nbytes);
282 value += ((guint64)*ptr++) << 40;
284 value += ((guint64)*ptr++) << 32;
286 value += ((guint64)*ptr++) << 24;
288 value += ((guint64)*ptr++) << 16;
290 value += ((guint64)*ptr++) << 8;
297 static void dissect_feature_options(proto_tree *dccp_options_tree, tvbuff_t *tvb, int offset, guint8 option_len,
300 guint8 feature_number = tvb_get_guint8(tvb, offset + 2);
301 proto_item *dccp_item, *hidden_item;
304 hidden_item = proto_tree_add_uint(dccp_options_tree, hf_dccp_feature_number, tvb, offset + 2, 1, feature_number);
305 PROTO_ITEM_SET_HIDDEN(hidden_item);
307 dccp_item = proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "%s(",
308 val_to_str(option_type, dccp_feature_options_vals, "Unknown Type"));
310 /* decode the feature according to whether it is server-priority (list) or NN (single number) */
311 switch (feature_number) {
312 /* Server Priority features (RFC 4340, 6.3.1) */
313 case 1: /* Congestion Control ID (CCID); fall through */
314 case 2: /* Allow Short Seqnos; fall through */
315 case 4: /* ECN Incapable; fall through */
316 case 6: /* Send Ack Vector; fall through */
317 case 7: /* Send NDP Count; fall through */
318 case 8: /* Minimum Checksum Coverage; fall through */
319 case 9: /* Check Data Checksum; fall through */
320 case 192: /* Send Loss Event Rate, RFC 4342, section 8.4 */
321 proto_item_append_text(dccp_item, "%s",
322 val_to_str(feature_number, dccp_feature_numbers_vals, "Unknown Type"));
323 for (i = 0; i < option_len - 3; i++)
324 proto_item_append_text(dccp_item, "%s %d", i? "," : "", tvb_get_guint8(tvb, offset + 3 + i));
326 /* Non-negotiable features (RFC 4340, 6.3.2) */
327 case 3: /* Sequence Window; fall through */
328 case 5: /* Ack Ratio */
329 proto_item_append_text(dccp_item, "%s",
330 val_to_str(feature_number, dccp_feature_numbers_vals, "Unknown Type"));
332 if (option_len > 3) /* could be empty Confirm */
333 proto_item_append_text(dccp_item, " %" G_GINT64_MODIFIER "u", tvb_get_ntoh_var(tvb, offset + 3, option_len - 3));
335 /* Reserved, specific, or unknown features */
337 if (feature_number == 0 ||
338 (feature_number >= 10 && feature_number <= 127))
339 proto_item_append_text(dccp_item, "Reserved feature number %d", feature_number);
340 else if (feature_number >= 193)
341 proto_item_append_text(dccp_item, "CCID-specific feature number %d", feature_number);
343 proto_item_append_text(dccp_item, "Unknown feature number %d", feature_number);
346 proto_item_append_text(dccp_item, ")");
350 * This function dissects DCCP options
352 static void dissect_options(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *dccp_options_tree, proto_tree *tree _U_, e_dccphdr *dccph _U_,
356 /* if here I'm sure there is at least offset_end - offset_start bytes in tvb and it should be options */
357 int offset=offset_start;
358 guint8 option_type = 0;
359 guint8 option_len = 0;
362 proto_item *dccp_item = NULL;
363 proto_item *hidden_item;
365 while( offset < offset_end ) {
367 /* DBG("offset==%d\n", offset); */
369 /* first byte is the option type */
370 option_type = tvb_get_guint8(tvb, offset);
371 hidden_item = proto_tree_add_uint(dccp_options_tree, hf_dccp_option_type, tvb, offset, 1, option_type);
372 PROTO_ITEM_SET_HIDDEN(hidden_item);
374 if (option_type >= 32) { /* variable length options */
376 if(!tvb_bytes_exist(tvb, offset, 1)) {
377 /* DBG("malformed\n"); */
378 hidden_item = proto_tree_add_boolean(dccp_options_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
379 PROTO_ITEM_SET_HIDDEN(hidden_item);
380 THROW(ReportedBoundsError);
383 option_len = tvb_get_guint8(tvb, offset + 1);
385 if (option_len < 2) {
386 /* DBG("malformed\n"); */
387 hidden_item = proto_tree_add_boolean(dccp_options_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
388 PROTO_ITEM_SET_HIDDEN(hidden_item);
389 THROW(ReportedBoundsError);
392 if(!tvb_bytes_exist(tvb, offset, option_len)) {
393 /* DBG("malformed\n"); */
394 hidden_item = proto_tree_add_boolean(dccp_options_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
395 PROTO_ITEM_SET_HIDDEN(hidden_item);
396 THROW(ReportedBoundsError);
399 } else { /* 1byte options */
403 switch (option_type) {
406 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Padding");
410 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Mandatory");
414 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Slow Receiver");
421 dissect_feature_options(dccp_options_tree, tvb, offset, option_len, option_type);
425 dccp_item = proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Init Cookie(");
426 for (i = 0; i < option_len - 2; i++) {
428 proto_item_append_text(dccp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
430 proto_item_append_text(dccp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
432 proto_item_append_text(dccp_item, ")");
437 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "NDP Count too long (max 6 bytes)");
439 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "NDP Count: %" G_GINT64_MODIFIER "u",
440 tvb_get_ntoh_var(tvb, offset + 2, option_len - 2));
444 dccp_item = proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Ack Vector [Nonce 0]:");
445 for (i = 0; i < option_len - 2; i++)
446 proto_item_append_text(dccp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
450 dccp_item = proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Ack Vector [Nonce 1]:");
451 for (i = 0; i < option_len - 2; i++)
452 proto_item_append_text(dccp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
453 proto_item_append_text(dccp_item, ")");
457 dccp_item = proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Data Dropped:");
458 for (i = 0; i < option_len - 2; i++)
459 proto_item_append_text(dccp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
464 proto_tree_add_uint(dccp_options_tree, hf_dccp_timestamp, tvb, offset + 2, 4,
465 tvb_get_ntohl(tvb, offset + 2));
467 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len,
468 "Timestamp too long [%u != 6]", option_len);
473 proto_tree_add_uint(dccp_options_tree, hf_dccp_timestamp_echo, tvb, offset + 2, 4,
474 tvb_get_ntohl(tvb, offset + 2));
475 else if (option_len==8) {
476 proto_tree_add_uint(dccp_options_tree, hf_dccp_timestamp_echo, tvb, offset + 2, 4,
477 tvb_get_ntohl(tvb, offset + 2));
479 proto_tree_add_uint(dccp_options_tree, hf_dccp_elapsed_time, tvb, offset + 6, 2,
480 tvb_get_ntohs(tvb, offset + 6));
481 } else if (option_len==10) {
482 proto_tree_add_uint(dccp_options_tree, hf_dccp_timestamp_echo, tvb, offset + 2, 4,
483 tvb_get_ntohl(tvb, offset + 2));
485 proto_tree_add_uint(dccp_options_tree, hf_dccp_elapsed_time, tvb, offset + 6, 4,
486 tvb_get_ntohl(tvb, offset + 6));
488 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Wrong Timestamp Echo length");
493 proto_tree_add_uint(dccp_options_tree, hf_dccp_elapsed_time, tvb, offset + 2, 2,
494 tvb_get_ntohs(tvb, offset + 2));
495 else if (option_len==6)
496 proto_tree_add_uint(dccp_options_tree, hf_dccp_elapsed_time, tvb, offset + 2, 4,
497 tvb_get_ntohl(tvb, offset + 2));
499 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Wrong Elapsed Time length");
504 proto_tree_add_uint(dccp_options_tree, hf_dccp_data_checksum, tvb, offset + 2, 4,
505 tvb_get_ntohl(tvb, offset + 2));
507 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Wrong Data checksum length");
509 case 192: /* RFC 4342, 8.5 */
510 if(option_len == 6) {
511 p = tvb_get_ntohl(tvb, offset + 2);
512 /* According to the comment in section 8.5 of RFC 4342, 0xffffffff can mean zero */
514 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: 0 (or max)");
516 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: %u", p);
518 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Wrong CCID3 Loss Event Rate length");
520 case 193: /* RFC 4342, 8.6 */
521 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "CCID3 Loss Intervals");
522 /* FIXME: not implemented and apparently not used by any implementation so far */
524 case 194: /* RFC 4342, 8.3 */
526 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "CCID3 Receive Rate: %u bytes/sec",
527 tvb_get_ntohl(tvb, offset + 2));
529 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Wrong CCID3 Receive Rate length");
532 if(((option_type >= 45) && (option_type <= 127)) ||
533 ((option_type >= 3) && (option_type <= 31))) {
534 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Reserved");
538 if (option_type >= 128) {
539 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "CCID option %d", option_type);
543 /* if here we don't know this option */
544 proto_tree_add_text(dccp_options_tree, tvb, offset, option_len, "Unknown");
549 offset+=option_len; /* Skip over the dissected option */
553 /* compute DCCP checksum coverage according to RFC 4340, section 9 */
554 static inline guint dccp_csum_coverage(const e_dccphdr *dccph, guint len)
558 if (dccph->cscov == 0)
560 cov = (dccph->data_offset + dccph->cscov - 1) * sizeof(guint32);
561 return (cov > len)? len : cov;
564 static void dissect_dccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
566 proto_tree *dccp_tree = NULL;
567 proto_tree *dccp_options_tree = NULL;
568 proto_item *dccp_item = NULL;
569 proto_item *hidden_item;
573 guint16 computed_cksum;
576 guint reported_len = 0;
577 guint advertised_dccp_header_len = 0;
578 guint options_len = 0;
581 /* get at least a full message header */
582 if(tvb_length(tvb) < DCCP_HDR_LEN_MIN) {
583 /* DBG("malformed\n"); */
585 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
586 PROTO_ITEM_SET_HIDDEN(hidden_item);
588 if (check_col(pinfo->cinfo, COL_INFO))
589 col_set_str(pinfo->cinfo, COL_INFO, "Packet too short");
590 THROW(ReportedBoundsError);
593 dccph=ep_alloc(sizeof(e_dccphdr));
595 memset(dccph, 0, sizeof(e_dccphdr));
597 SET_ADDRESS(&dccph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
598 SET_ADDRESS(&dccph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
600 if (check_col(pinfo->cinfo, COL_PROTOCOL))
601 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCCP");
602 if (check_col(pinfo->cinfo, COL_INFO))
603 col_clear(pinfo->cinfo, COL_INFO);
605 /* Extract generic header */
606 dccph->sport=tvb_get_ntohs(tvb, offset);
607 /* DBG("dccph->sport: %d\n", dccph->sport); */
608 dccph->dport=tvb_get_ntohs(tvb, offset+2);
609 /* DBG("dccph->dport: %d\n", dccph->dport); */
611 /* update pinfo structure. I guess I have to do it, because this is a transport protocol dissector. Right? */
612 pinfo->ptype=PT_DCCP;
613 pinfo->srcport=dccph->sport;
614 pinfo->destport=dccph->dport;
616 dccph->data_offset=tvb_get_guint8(tvb, offset+4);
617 /* DBG("dccph->data_offset: %d\n", dccph->data_offset); */
618 dccph->cscov=tvb_get_guint8(tvb, offset+5)&0x0F;
619 /* DBG("dccph->cscov: %d\n", dccph->cscov); */
620 dccph->ccval=tvb_get_guint8(tvb, offset+5) &0xF0;
622 /* DBG("dccph->ccval: %d\n", dccph->ccval); */
623 dccph->checksum=tvb_get_ntohs(tvb, offset+6);
624 /* DBG("dccph->checksum: %d\n", dccph->checksum); */
625 dccph->reserved1=tvb_get_guint8(tvb, offset+8)&0xE0;
626 dccph->reserved1>>=5;
627 /* DBG("dccph->reserved1: %d\n", dccph->reserved1); */
628 dccph->type=tvb_get_guint8(tvb, offset+8)&0x1E;
630 /* DBG("dccph->type: %d\n", dccph->type); */
631 dccph->x=tvb_get_guint8(tvb, offset+8)&0x01;
632 /* DBG("dccph->x: %d\n", dccph->x); */
634 if(tvb_length(tvb) < DCCP_HDR_LEN) { /* at least 16 bytes */
635 /* DBG("malformed\n"); */
636 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
637 PROTO_ITEM_SET_HIDDEN(hidden_item);
638 THROW(ReportedBoundsError);
640 dccph->reserved2=tvb_get_guint8(tvb, offset+9);
641 /* DBG("dccph->reserved2: %u\n", dccph->reserved2); */
642 dccph->seq=tvb_get_ntohs(tvb, offset+10);
644 dccph->seq+=tvb_get_ntohl(tvb, offset+12);
645 /* DBG("dccph->seq[48bits]: %" G_GINT64_MODIFIER "u\n", dccph->seq); */
647 dccph->seq=tvb_get_guint8(tvb, offset+9);
649 dccph->seq+=tvb_get_ntohs(tvb, offset+10);
650 /* DBG("dccph->seq[24bits]: %" G_GINT64_MODIFIER "u\n", dccph->seq); */
653 if (check_col(pinfo->cinfo, COL_INFO))
654 col_add_fstr(pinfo->cinfo, COL_INFO, "%s > %s [%s] Seq=%" G_GINT64_MODIFIER "u",
655 get_dccp_port(dccph->sport),
656 get_dccp_port(dccph->dport),
657 val_to_str(dccph->type, dccp_packet_type_vals, "Unknown Type"),
662 if(dccp_summary_in_tree) {
664 proto_tree_add_protocol_format(tree, proto_dccp, tvb, offset, dccph->data_offset*4,
665 "Datagram Congestion Control Protocol, Src Port: %s (%u), Dst Port: %s (%u)"
666 " [%s] Seq=%" G_GINT64_MODIFIER "u",
667 get_dccp_port(dccph->sport), dccph->sport,
668 get_dccp_port(dccph->dport), dccph->dport,
669 val_to_str(dccph->type, dccp_packet_type_vals, "Unknown Type"),
672 dccp_item = proto_tree_add_item(tree, proto_dccp, tvb, offset, 8, FALSE);
675 dccp_tree = proto_item_add_subtree(dccp_item, ett_dccp);
677 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_srcport, tvb, offset, 2, dccph->sport,
678 "%s (%u)", get_dccp_port(dccph->sport), dccph->sport);
679 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_dstport, tvb, offset + 2, 2, dccph->dport,
680 "%s (%u)", get_dccp_port(dccph->dport), dccph->dport);
682 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_port, tvb, offset, 2, dccph->sport);
683 PROTO_ITEM_SET_HIDDEN(hidden_item);
684 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_port, tvb, offset + 2, 2, dccph->dport);
685 PROTO_ITEM_SET_HIDDEN(hidden_item);
687 proto_tree_add_uint(dccp_tree, hf_dccp_data_offset, tvb, offset + 4, 1, dccph->data_offset);
688 proto_tree_add_uint(dccp_tree, hf_dccp_ccval, tvb, offset + 5, 1, dccph->ccval);
689 proto_tree_add_uint(dccp_tree, hf_dccp_cscov, tvb, offset + 5, 1, dccph->cscov);
691 /* checksum analysis taken from packet-udp (difference: mandatory checksums in DCCP) */
693 reported_len = tvb_reported_length(tvb);
694 len = tvb_length(tvb);
695 if (!pinfo->fragmented && len >= reported_len) {
697 /* The packet isn't part of a fragmented datagram and isn't
698 truncated, so we can checksum it.
699 XXX - make a bigger scatter-gather list once we do fragment
702 if (dccp_check_checksum) {
704 /* Set up the fields of the pseudo-header. */
705 cksum_vec[0].ptr = pinfo->src.data;
706 cksum_vec[0].len = pinfo->src.len;
707 cksum_vec[1].ptr = pinfo->dst.data;
708 cksum_vec[1].len = pinfo->dst.len;
709 cksum_vec[2].ptr = (const guint8 *)&phdr;
710 switch (pinfo->src.type) {
713 phdr[0] = g_htonl((IP_PROTO_DCCP<<16) + reported_len);
714 cksum_vec[2].len = 4;
717 phdr[0] = g_htonl(reported_len);
718 phdr[1] = g_htonl(IP_PROTO_DCCP);
719 cksum_vec[2].len = 8;
723 /* DCCP runs only atop IPv4 and IPv6.... */
724 /*DISSECTOR_ASSERT_NOT_REACHED();*/
727 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len);
728 cksum_vec[3].len = dccp_csum_coverage(dccph, reported_len);
729 computed_cksum = in_cksum(&cksum_vec[0], 4);
730 if (computed_cksum == 0) {
731 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb,
732 offset + 6, 2, dccph->checksum,
733 "0x%04x [correct]", dccph->checksum);
735 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_checksum_bad, tvb, offset + 6, 2, TRUE);;
736 PROTO_ITEM_SET_HIDDEN(hidden_item);
737 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb, offset + 6, 2, dccph->checksum,
738 "0x%04x [incorrect, should be 0x%04x]", dccph->checksum,
739 in_cksum_shouldbe(dccph->checksum, computed_cksum));
742 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb,
743 offset + 6, 2, dccph->checksum, "0x%04x", dccph->checksum);
746 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb,
747 offset + 6, 2, dccph->checksum, "0x%04x", dccph->checksum);
750 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_res1, tvb, offset + 8, 1, dccph->reserved1);
751 PROTO_ITEM_SET_HIDDEN(hidden_item);
752 proto_tree_add_uint(dccp_tree, hf_dccp_type, tvb, offset + 8, 1, dccph->type);
753 proto_tree_add_boolean(dccp_tree, hf_dccp_x, tvb, offset + 8, 1, dccph->x);
755 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_res2, tvb, offset + 9, 1, dccph->reserved2);
756 PROTO_ITEM_SET_HIDDEN(hidden_item);
757 proto_tree_add_uint64(dccp_tree, hf_dccp_seq, tvb, offset + 10, 6, dccph->seq);
759 proto_tree_add_uint64(dccp_tree, hf_dccp_seq, tvb, offset + 9, 3, dccph->seq);
765 offset+=16; /* Skip over extended Generic header */
767 offset+=12; /* Skip over not extended Generic header */
769 /* dissecting type depending additional fields */
770 switch(dccph->type) {
772 case 0x0: /* DCCP-Request */
773 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
775 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
778 dccph->service_code=tvb_get_ntohl(tvb, offset);
780 proto_tree_add_uint(dccp_tree, hf_dccp_service_code, tvb, offset, 4, dccph->service_code);
781 if (check_col(pinfo->cinfo, COL_INFO))
782 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dccph->service_code);
784 offset+=4; /* Skip over service code */
787 case 0x1: /* DCCP-Response */
788 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
790 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
793 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
795 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
796 PROTO_ITEM_SET_HIDDEN(hidden_item);
798 dccph->ack=tvb_get_ntohs(tvb, offset+2);
800 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
803 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
804 if (check_col(pinfo->cinfo, COL_INFO))
805 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
807 offset+=8; /* Skip over Acknowledgement Number Subheader */
809 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
811 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
814 dccph->service_code=tvb_get_ntohl(tvb, offset);
816 proto_tree_add_uint(dccp_tree, hf_dccp_service_code, tvb, offset, 4, dccph->service_code);
817 if (check_col(pinfo->cinfo, COL_INFO))
818 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dccph->service_code);
820 offset+=4; /* Skip over service code */
823 case 0x2: /* DCCP-Data */
824 /* nothing to dissect */
827 case 0x3: /* DCCP-Ack */
828 case 0x4: /* DCCP-DataAck */
830 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
832 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
835 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
837 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
838 PROTO_ITEM_SET_HIDDEN(hidden_item);
840 dccph->ack=tvb_get_ntohs(tvb, offset+2);
842 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
844 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
845 if (check_col(pinfo->cinfo, COL_INFO))
846 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
848 offset+=8; /* Skip over Acknowledgement Number Subheader */
850 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
852 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
855 dccph->ack_reserved=tvb_get_guint8(tvb, offset);
857 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 1, dccph->ack_reserved);
858 PROTO_ITEM_SET_HIDDEN(hidden_item);
860 dccph->ack=tvb_get_guint8(tvb, offset+1);
862 dccph->ack+=tvb_get_ntohs(tvb, offset+2);
864 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 1, 3, dccph->ack);
865 if (check_col(pinfo->cinfo, COL_INFO))
866 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
868 offset+=4; /* Skip over Acknowledgement Number Subheader */
872 case 0x7: /* DCCP-Reset */
873 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
875 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
878 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
880 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
881 PROTO_ITEM_SET_HIDDEN(hidden_item);
883 dccph->ack=tvb_get_ntohs(tvb, offset+2);
885 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
887 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
888 if (check_col(pinfo->cinfo, COL_INFO))
889 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
891 offset+=8; /* Skip over Acknowledgement Number Subheader */
893 dccph->reset_code=tvb_get_guint8(tvb, offset);
894 dccph->data1=tvb_get_guint8(tvb, offset+1);
895 dccph->data2=tvb_get_guint8(tvb, offset+2);
896 dccph->data3=tvb_get_guint8(tvb, offset+3);
898 proto_tree_add_uint(dccp_tree, hf_dccp_reset_code, tvb, offset, 1, dccph->reset_code);
899 proto_tree_add_uint(dccp_tree, hf_dccp_data1, tvb, offset + 1, 1, dccph->data1);
900 proto_tree_add_uint(dccp_tree, hf_dccp_data2, tvb, offset + 2, 1, dccph->data2);
901 proto_tree_add_uint(dccp_tree, hf_dccp_data3, tvb, offset + 3, 1, dccph->data3);
903 if (check_col(pinfo->cinfo, COL_INFO))
904 col_append_fstr(pinfo->cinfo, COL_INFO, " (code=%s)", val_to_str(dccph->reset_code, dccp_reset_code_vals, "Unknown"));
906 offset+=4; /* Skip over Reset Code and data123 */
909 case 0x5: /* DCCP-CloseReq */
910 case 0x6: /* DCCP-Close */
911 case 0x8: /* DCCP-Sync */
912 case 0x9: /* DCCP-SyncAck */
913 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
915 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
918 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
920 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
921 PROTO_ITEM_SET_HIDDEN(hidden_item);
923 dccph->ack=tvb_get_ntohs(tvb, offset+2);
925 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
927 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
928 if (check_col(pinfo->cinfo, COL_INFO))
929 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
931 offset+=8; /* Skip over Acknowledgement Number Subheader */
936 proto_tree_add_text(dccp_tree, tvb, offset, -1, "Reserved packet type: unable to dissect further");
941 /* note: data_offset is the offset from the start of the packet's DCCP header to the
942 * start of its application data area, in 32-bit words.
945 /* it's time to do some checks */
946 advertised_dccp_header_len = dccph->data_offset*4;
947 options_len = advertised_dccp_header_len - offset;
949 if ( advertised_dccp_header_len > DCCP_HDR_LEN_MAX ) {
951 proto_tree_add_text(dccp_tree, tvb, 4, 2,
952 "bogus data offset, advertised header length (%d) is larger than max (%d)",
953 advertised_dccp_header_len, DCCP_HDR_LEN_MAX);
957 if(tvb_length(tvb) < advertised_dccp_header_len) {
959 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet: missing %d bytes of DCCP header",
960 advertised_dccp_header_len - tvb_reported_length_remaining(tvb, offset));
964 if(options_len > DCCP_OPT_LEN_MAX) {
965 /* DBG("malformed\n"); */
967 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
968 PROTO_ITEM_SET_HIDDEN(hidden_item);
970 THROW(ReportedBoundsError);
974 /* Dissecting Options (if here we have at least (advertised_dccp_header_len - offset) bytes of options) */
975 if(advertised_dccp_header_len == offset) {
976 ; /* ok no options, no need to skip over */
977 } else if (advertised_dccp_header_len < offset) {
979 proto_tree_add_text(dccp_tree, tvb, 4, 2,
980 "bogus data offset, advertised header length (%d) is shorter than expected",
981 advertised_dccp_header_len);
982 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
983 PROTO_ITEM_SET_HIDDEN(hidden_item);
985 THROW(ReportedBoundsError);
988 dccp_item = proto_tree_add_none_format(dccp_tree, hf_dccp_options, tvb, offset, options_len, "Options: (%u bytes)", options_len);
989 dccp_options_tree = proto_item_add_subtree(dccp_item, ett_dccp_options);
991 dissect_options(tvb, pinfo, dccp_options_tree, tree, dccph, offset, offset + options_len);
994 offset+=options_len; /* Skip over Options */
996 /* Queuing tap data */
997 tap_queue_packet(dccp_tap, pinfo, dccph);
999 /* Call sub-dissectors */
1001 if (!pinfo->in_error_pkt || tvb_length_remaining(tvb, offset) > 0)
1002 decode_dccp_ports(tvb, offset, pinfo, tree, dccph->sport, dccph->dport);
1006 void proto_register_dccp(void)
1008 module_t *dccp_module;
1010 static hf_register_info hf[] = {
1012 { "Source Port", "dccp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
1016 { "Destination Port", "dccp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
1020 { "Source or Destination Port", "dccp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
1023 { &hf_dccp_data_offset,
1024 { "Data Offset", "dccp.data_offset", FT_UINT8, BASE_DEC, NULL, 0x0,
1028 { "CCVal", "dccp.ccval", FT_UINT8, BASE_DEC, NULL, 0x0,
1032 { "Checksum Coverage", "dccp.cscov", FT_UINT8, BASE_DEC, NULL, 0x0,
1035 { &hf_dccp_checksum_bad,
1036 { "Bad Checksum", "dccp.checksum_bad", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1039 { &hf_dccp_checksum,
1040 { "Checksum", "dccp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1044 { "Reserved", "dccp.res1", FT_UINT8, BASE_HEX, NULL, 0x0,
1048 { "Reserved", "dccp.res2", FT_UINT8, BASE_HEX, NULL, 0x0,
1052 { "Type", "dccp.type", FT_UINT8, BASE_DEC, VALS(dccp_packet_type_vals), 0x0,
1056 { "Extended Sequence Numbers", "dccp.x", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1060 { "Sequence Number", "dccp.seq", FT_UINT64, BASE_DEC, NULL, 0x0,
1064 { "Reserved", "dccp.ack_res", FT_UINT16, BASE_HEX, NULL, 0x0,
1068 { "Acknowledgement Number", "dccp.ack", FT_UINT64, BASE_DEC, NULL, 0x0,
1071 { &hf_dccp_service_code,
1072 { "Service Code", "dccp.service_code", FT_UINT32, BASE_DEC, NULL, 0x0,
1075 { &hf_dccp_reset_code,
1076 { "Reset Code", "dccp.reset_code", FT_UINT8, BASE_DEC, VALS(dccp_reset_code_vals), 0x0,
1080 { "Data 1", "dccp.data1", FT_UINT8, BASE_DEC, NULL, 0x0,
1084 { "Data 2", "dccp.data2", FT_UINT8, BASE_DEC, NULL, 0x0,
1088 { "Data 3", "dccp.data3", FT_UINT8, BASE_DEC, NULL, 0x0,
1091 { &hf_dccp_option_type,
1092 { "Option Type", "dccp.option_type", FT_UINT8, BASE_DEC, NULL, 0x0,
1095 { &hf_dccp_feature_number,
1096 { "Feature Number", "dccp.feature_number", FT_UINT8, BASE_DEC, NULL, 0x0,
1099 { &hf_dccp_ndp_count,
1100 { "NDP Count", "dccp.ndp_count", FT_UINT64, BASE_DEC, NULL, 0x0,
1103 { &hf_dccp_timestamp,
1104 { "Timestamp", "dccp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
1107 { &hf_dccp_timestamp_echo,
1108 { "Timestamp Echo", "dccp.timestamp_echo", FT_UINT32, BASE_DEC, NULL, 0x0,
1111 { &hf_dccp_elapsed_time,
1112 { "Elapsed Time", "dccp.elapsed_time", FT_UINT32, BASE_DEC, NULL, 0x0,
1115 { &hf_dccp_data_checksum,
1116 { "Data Checksum", "dccp.checksum_data", FT_UINT32, BASE_HEX, NULL, 0x0,
1119 { &hf_dccp_malformed,
1120 { "Malformed", "dccp.malformed", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1124 { "Options", "dccp.options", FT_NONE, BASE_DEC, NULL, 0x0,
1125 "DCCP Options fields", HFILL }}
1129 static gint *ett[] = {
1134 proto_dccp = proto_register_protocol("Datagram Congestion Control Protocol", "DCCP", "dccp");
1135 proto_register_field_array(proto_dccp, hf, array_length(hf));
1136 proto_register_subtree_array(ett, array_length(ett));
1139 dccp_subdissector_table = register_dissector_table("dccp.port", "DCCP port", FT_UINT16, BASE_DEC);
1140 register_heur_dissector_list("dccp", &heur_subdissector_list);
1142 /* reg preferences */
1143 dccp_module = prefs_register_protocol(proto_dccp, NULL);
1144 prefs_register_bool_preference(dccp_module, "summary_in_tree",
1145 "Show DCCP summary in protocol tree",
1146 "Whether the DCCP summary line should be shown in the protocol tree",
1147 &dccp_summary_in_tree);
1149 prefs_register_bool_preference(dccp_module, "try_heuristic_first",
1150 "Try heuristic sub-dissectors first",
1151 "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector "
1152 "registered to a specific port",
1153 &try_heuristic_first);
1155 prefs_register_bool_preference(dccp_module, "check_checksum",
1156 "Check the validity of the DCCP checksum when possible",
1157 "Whether to check the validity of the DCCP checksum",
1158 &dccp_check_checksum);
1161 void proto_reg_handoff_dccp(void)
1163 dissector_handle_t dccp_handle;
1165 dccp_handle = create_dissector_handle(dissect_dccp, proto_dccp);
1166 dissector_add("ip.proto", IP_PROTO_DCCP, dccp_handle);
1167 data_handle = find_dissector("data");
1168 dccp_tap = register_tap("dccp");