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 seqnums */
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 Seqnums"},
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 Seqnums; 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 col_set_str(pinfo->cinfo, COL_INFO, "Packet too short");
589 THROW(ReportedBoundsError);
592 dccph=ep_alloc(sizeof(e_dccphdr));
594 memset(dccph, 0, sizeof(e_dccphdr));
596 SET_ADDRESS(&dccph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
597 SET_ADDRESS(&dccph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
599 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCCP");
600 if (check_col(pinfo->cinfo, COL_INFO))
601 col_clear(pinfo->cinfo, COL_INFO);
603 /* Extract generic header */
604 dccph->sport=tvb_get_ntohs(tvb, offset);
605 /* DBG("dccph->sport: %d\n", dccph->sport); */
606 dccph->dport=tvb_get_ntohs(tvb, offset+2);
607 /* DBG("dccph->dport: %d\n", dccph->dport); */
609 /* update pinfo structure. I guess I have to do it, because this is a transport protocol dissector. Right? */
610 pinfo->ptype=PT_DCCP;
611 pinfo->srcport=dccph->sport;
612 pinfo->destport=dccph->dport;
614 dccph->data_offset=tvb_get_guint8(tvb, offset+4);
615 /* DBG("dccph->data_offset: %d\n", dccph->data_offset); */
616 dccph->cscov=tvb_get_guint8(tvb, offset+5)&0x0F;
617 /* DBG("dccph->cscov: %d\n", dccph->cscov); */
618 dccph->ccval=tvb_get_guint8(tvb, offset+5) &0xF0;
620 /* DBG("dccph->ccval: %d\n", dccph->ccval); */
621 dccph->checksum=tvb_get_ntohs(tvb, offset+6);
622 /* DBG("dccph->checksum: %d\n", dccph->checksum); */
623 dccph->reserved1=tvb_get_guint8(tvb, offset+8)&0xE0;
624 dccph->reserved1>>=5;
625 /* DBG("dccph->reserved1: %d\n", dccph->reserved1); */
626 dccph->type=tvb_get_guint8(tvb, offset+8)&0x1E;
628 /* DBG("dccph->type: %d\n", dccph->type); */
629 dccph->x=tvb_get_guint8(tvb, offset+8)&0x01;
630 /* DBG("dccph->x: %d\n", dccph->x); */
632 if(tvb_length(tvb) < DCCP_HDR_LEN) { /* at least 16 bytes */
633 /* DBG("malformed\n"); */
634 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
635 PROTO_ITEM_SET_HIDDEN(hidden_item);
636 THROW(ReportedBoundsError);
638 dccph->reserved2=tvb_get_guint8(tvb, offset+9);
639 /* DBG("dccph->reserved2: %u\n", dccph->reserved2); */
640 dccph->seq=tvb_get_ntohs(tvb, offset+10);
642 dccph->seq+=tvb_get_ntohl(tvb, offset+12);
643 /* DBG("dccph->seq[48bits]: %" G_GINT64_MODIFIER "u\n", dccph->seq); */
645 dccph->seq=tvb_get_guint8(tvb, offset+9);
647 dccph->seq+=tvb_get_ntohs(tvb, offset+10);
648 /* DBG("dccph->seq[24bits]: %" G_GINT64_MODIFIER "u\n", dccph->seq); */
651 if (check_col(pinfo->cinfo, COL_INFO))
652 col_add_fstr(pinfo->cinfo, COL_INFO, "%s > %s [%s] Seq=%" G_GINT64_MODIFIER "u",
653 get_dccp_port(dccph->sport),
654 get_dccp_port(dccph->dport),
655 val_to_str(dccph->type, dccp_packet_type_vals, "Unknown Type"),
660 if(dccp_summary_in_tree) {
662 proto_tree_add_protocol_format(tree, proto_dccp, tvb, offset, dccph->data_offset*4,
663 "Datagram Congestion Control Protocol, Src Port: %s (%u), Dst Port: %s (%u)"
664 " [%s] Seq=%" G_GINT64_MODIFIER "u",
665 get_dccp_port(dccph->sport), dccph->sport,
666 get_dccp_port(dccph->dport), dccph->dport,
667 val_to_str(dccph->type, dccp_packet_type_vals, "Unknown Type"),
670 dccp_item = proto_tree_add_item(tree, proto_dccp, tvb, offset, 8, FALSE);
673 dccp_tree = proto_item_add_subtree(dccp_item, ett_dccp);
675 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_srcport, tvb, offset, 2, dccph->sport,
676 "%s (%u)", get_dccp_port(dccph->sport), dccph->sport);
677 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_dstport, tvb, offset + 2, 2, dccph->dport,
678 "%s (%u)", get_dccp_port(dccph->dport), dccph->dport);
680 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_port, tvb, offset, 2, dccph->sport);
681 PROTO_ITEM_SET_HIDDEN(hidden_item);
682 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_port, tvb, offset + 2, 2, dccph->dport);
683 PROTO_ITEM_SET_HIDDEN(hidden_item);
685 proto_tree_add_uint(dccp_tree, hf_dccp_data_offset, tvb, offset + 4, 1, dccph->data_offset);
686 proto_tree_add_uint(dccp_tree, hf_dccp_ccval, tvb, offset + 5, 1, dccph->ccval);
687 proto_tree_add_uint(dccp_tree, hf_dccp_cscov, tvb, offset + 5, 1, dccph->cscov);
689 /* checksum analysis taken from packet-udp (difference: mandatory checksums in DCCP) */
691 reported_len = tvb_reported_length(tvb);
692 len = tvb_length(tvb);
693 if (!pinfo->fragmented && len >= reported_len) {
695 /* The packet isn't part of a fragmented datagram and isn't
696 truncated, so we can checksum it.
697 XXX - make a bigger scatter-gather list once we do fragment
700 if (dccp_check_checksum) {
702 /* Set up the fields of the pseudo-header. */
703 cksum_vec[0].ptr = pinfo->src.data;
704 cksum_vec[0].len = pinfo->src.len;
705 cksum_vec[1].ptr = pinfo->dst.data;
706 cksum_vec[1].len = pinfo->dst.len;
707 cksum_vec[2].ptr = (const guint8 *)&phdr;
708 switch (pinfo->src.type) {
711 phdr[0] = g_htonl((IP_PROTO_DCCP<<16) + reported_len);
712 cksum_vec[2].len = 4;
715 phdr[0] = g_htonl(reported_len);
716 phdr[1] = g_htonl(IP_PROTO_DCCP);
717 cksum_vec[2].len = 8;
721 /* DCCP runs only atop IPv4 and IPv6.... */
722 /*DISSECTOR_ASSERT_NOT_REACHED();*/
725 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len);
726 cksum_vec[3].len = dccp_csum_coverage(dccph, reported_len);
727 computed_cksum = in_cksum(&cksum_vec[0], 4);
728 if (computed_cksum == 0) {
729 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb,
730 offset + 6, 2, dccph->checksum,
731 "0x%04x [correct]", dccph->checksum);
733 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_checksum_bad, tvb, offset + 6, 2, TRUE);;
734 PROTO_ITEM_SET_HIDDEN(hidden_item);
735 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb, offset + 6, 2, dccph->checksum,
736 "0x%04x [incorrect, should be 0x%04x]", dccph->checksum,
737 in_cksum_shouldbe(dccph->checksum, computed_cksum));
740 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb,
741 offset + 6, 2, dccph->checksum, "0x%04x", dccph->checksum);
744 proto_tree_add_uint_format_value(dccp_tree, hf_dccp_checksum, tvb,
745 offset + 6, 2, dccph->checksum, "0x%04x", dccph->checksum);
748 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_res1, tvb, offset + 8, 1, dccph->reserved1);
749 PROTO_ITEM_SET_HIDDEN(hidden_item);
750 proto_tree_add_uint(dccp_tree, hf_dccp_type, tvb, offset + 8, 1, dccph->type);
751 proto_tree_add_boolean(dccp_tree, hf_dccp_x, tvb, offset + 8, 1, dccph->x);
753 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_res2, tvb, offset + 9, 1, dccph->reserved2);
754 PROTO_ITEM_SET_HIDDEN(hidden_item);
755 proto_tree_add_uint64(dccp_tree, hf_dccp_seq, tvb, offset + 10, 6, dccph->seq);
757 proto_tree_add_uint64(dccp_tree, hf_dccp_seq, tvb, offset + 9, 3, dccph->seq);
763 offset+=16; /* Skip over extended Generic header */
765 offset+=12; /* Skip over not extended Generic header */
767 /* dissecting type depending additional fields */
768 switch(dccph->type) {
770 case 0x0: /* DCCP-Request */
771 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
773 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
776 dccph->service_code=tvb_get_ntohl(tvb, offset);
778 proto_tree_add_uint(dccp_tree, hf_dccp_service_code, tvb, offset, 4, dccph->service_code);
779 if (check_col(pinfo->cinfo, COL_INFO))
780 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dccph->service_code);
782 offset+=4; /* Skip over service code */
785 case 0x1: /* DCCP-Response */
786 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
788 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
791 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
793 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
794 PROTO_ITEM_SET_HIDDEN(hidden_item);
796 dccph->ack=tvb_get_ntohs(tvb, offset+2);
798 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
801 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
802 if (check_col(pinfo->cinfo, COL_INFO))
803 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
805 offset+=8; /* Skip over Acknowledgement Number Subheader */
807 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
809 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
812 dccph->service_code=tvb_get_ntohl(tvb, offset);
814 proto_tree_add_uint(dccp_tree, hf_dccp_service_code, tvb, offset, 4, dccph->service_code);
815 if (check_col(pinfo->cinfo, COL_INFO))
816 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dccph->service_code);
818 offset+=4; /* Skip over service code */
821 case 0x2: /* DCCP-Data */
822 /* nothing to dissect */
825 case 0x3: /* DCCP-Ack */
826 case 0x4: /* DCCP-DataAck */
828 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
830 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
833 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
835 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
836 PROTO_ITEM_SET_HIDDEN(hidden_item);
838 dccph->ack=tvb_get_ntohs(tvb, offset+2);
840 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
842 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
843 if (check_col(pinfo->cinfo, COL_INFO))
844 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
846 offset+=8; /* Skip over Acknowledgement Number Subheader */
848 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
850 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
853 dccph->ack_reserved=tvb_get_guint8(tvb, offset);
855 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 1, dccph->ack_reserved);
856 PROTO_ITEM_SET_HIDDEN(hidden_item);
858 dccph->ack=tvb_get_guint8(tvb, offset+1);
860 dccph->ack+=tvb_get_ntohs(tvb, offset+2);
862 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 1, 3, dccph->ack);
863 if (check_col(pinfo->cinfo, COL_INFO))
864 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
866 offset+=4; /* Skip over Acknowledgement Number Subheader */
870 case 0x7: /* DCCP-Reset */
871 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
873 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
876 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
878 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
879 PROTO_ITEM_SET_HIDDEN(hidden_item);
881 dccph->ack=tvb_get_ntohs(tvb, offset+2);
883 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
885 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
886 if (check_col(pinfo->cinfo, COL_INFO))
887 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
889 offset+=8; /* Skip over Acknowledgement Number Subheader */
891 dccph->reset_code=tvb_get_guint8(tvb, offset);
892 dccph->data1=tvb_get_guint8(tvb, offset+1);
893 dccph->data2=tvb_get_guint8(tvb, offset+2);
894 dccph->data3=tvb_get_guint8(tvb, offset+3);
896 proto_tree_add_uint(dccp_tree, hf_dccp_reset_code, tvb, offset, 1, dccph->reset_code);
897 proto_tree_add_uint(dccp_tree, hf_dccp_data1, tvb, offset + 1, 1, dccph->data1);
898 proto_tree_add_uint(dccp_tree, hf_dccp_data2, tvb, offset + 2, 1, dccph->data2);
899 proto_tree_add_uint(dccp_tree, hf_dccp_data3, tvb, offset + 3, 1, dccph->data3);
901 if (check_col(pinfo->cinfo, COL_INFO))
902 col_append_fstr(pinfo->cinfo, COL_INFO, " (code=%s)", val_to_str(dccph->reset_code, dccp_reset_code_vals, "Unknown"));
904 offset+=4; /* Skip over Reset Code and data123 */
907 case 0x5: /* DCCP-CloseReq */
908 case 0x6: /* DCCP-Close */
909 case 0x8: /* DCCP-Sync */
910 case 0x9: /* DCCP-SyncAck */
911 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
913 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet");
916 dccph->ack_reserved=tvb_get_ntohs(tvb, offset);
918 hidden_item = proto_tree_add_uint(dccp_tree, hf_dccp_ack_res, tvb, offset, 2, dccph->ack_reserved);
919 PROTO_ITEM_SET_HIDDEN(hidden_item);
921 dccph->ack=tvb_get_ntohs(tvb, offset+2);
923 dccph->ack+=tvb_get_ntohl(tvb, offset+4);
925 proto_tree_add_uint64(dccp_tree, hf_dccp_ack, tvb, offset + 2, 6, dccph->ack);
926 if (check_col(pinfo->cinfo, COL_INFO))
927 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dccph->ack);
929 offset+=8; /* Skip over Acknowledgement Number Subheader */
934 proto_tree_add_text(dccp_tree, tvb, offset, -1, "Reserved packet type: unable to dissect further");
939 /* note: data_offset is the offset from the start of the packet's DCCP header to the
940 * start of its application data area, in 32-bit words.
943 /* it's time to do some checks */
944 advertised_dccp_header_len = dccph->data_offset*4;
945 options_len = advertised_dccp_header_len - offset;
947 if ( advertised_dccp_header_len > DCCP_HDR_LEN_MAX ) {
949 proto_tree_add_text(dccp_tree, tvb, 4, 2,
950 "bogus data offset, advertised header length (%d) is larger than max (%d)",
951 advertised_dccp_header_len, DCCP_HDR_LEN_MAX);
955 if(tvb_length(tvb) < advertised_dccp_header_len) {
957 proto_tree_add_text(dccp_tree, tvb, offset, -1, "too short packet: missing %d bytes of DCCP header",
958 advertised_dccp_header_len - tvb_reported_length_remaining(tvb, offset));
962 if(options_len > DCCP_OPT_LEN_MAX) {
963 /* DBG("malformed\n"); */
965 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
966 PROTO_ITEM_SET_HIDDEN(hidden_item);
968 THROW(ReportedBoundsError);
972 /* Dissecting Options (if here we have at least (advertised_dccp_header_len - offset) bytes of options) */
973 if(advertised_dccp_header_len == offset) {
974 ; /* ok no options, no need to skip over */
975 } else if (advertised_dccp_header_len < offset) {
977 proto_tree_add_text(dccp_tree, tvb, 4, 2,
978 "bogus data offset, advertised header length (%d) is shorter than expected",
979 advertised_dccp_header_len);
980 hidden_item = proto_tree_add_boolean(dccp_tree, hf_dccp_malformed, tvb, offset, 0, TRUE);
981 PROTO_ITEM_SET_HIDDEN(hidden_item);
983 THROW(ReportedBoundsError);
986 dccp_item = proto_tree_add_none_format(dccp_tree, hf_dccp_options, tvb, offset, options_len, "Options: (%u bytes)", options_len);
987 dccp_options_tree = proto_item_add_subtree(dccp_item, ett_dccp_options);
989 dissect_options(tvb, pinfo, dccp_options_tree, tree, dccph, offset, offset + options_len);
992 offset+=options_len; /* Skip over Options */
994 /* Queuing tap data */
995 tap_queue_packet(dccp_tap, pinfo, dccph);
997 /* Call sub-dissectors */
999 if (!pinfo->in_error_pkt || tvb_length_remaining(tvb, offset) > 0)
1000 decode_dccp_ports(tvb, offset, pinfo, tree, dccph->sport, dccph->dport);
1004 void proto_register_dccp(void)
1006 module_t *dccp_module;
1008 static hf_register_info hf[] = {
1010 { "Source Port", "dccp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
1014 { "Destination Port", "dccp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
1018 { "Source or Destination Port", "dccp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
1021 { &hf_dccp_data_offset,
1022 { "Data Offset", "dccp.data_offset", FT_UINT8, BASE_DEC, NULL, 0x0,
1026 { "CCVal", "dccp.ccval", FT_UINT8, BASE_DEC, NULL, 0x0,
1030 { "Checksum Coverage", "dccp.cscov", FT_UINT8, BASE_DEC, NULL, 0x0,
1033 { &hf_dccp_checksum_bad,
1034 { "Bad Checksum", "dccp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1037 { &hf_dccp_checksum,
1038 { "Checksum", "dccp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1042 { "Reserved", "dccp.res1", FT_UINT8, BASE_HEX, NULL, 0x0,
1046 { "Reserved", "dccp.res2", FT_UINT8, BASE_HEX, NULL, 0x0,
1050 { "Type", "dccp.type", FT_UINT8, BASE_DEC, VALS(dccp_packet_type_vals), 0x0,
1054 { "Extended Sequence Numbers", "dccp.x", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1058 { "Sequence Number", "dccp.seq", FT_UINT64, BASE_DEC, NULL, 0x0,
1062 { "Reserved", "dccp.ack_res", FT_UINT16, BASE_HEX, NULL, 0x0,
1066 { "Acknowledgement Number", "dccp.ack", FT_UINT64, BASE_DEC, NULL, 0x0,
1069 { &hf_dccp_service_code,
1070 { "Service Code", "dccp.service_code", FT_UINT32, BASE_DEC, NULL, 0x0,
1073 { &hf_dccp_reset_code,
1074 { "Reset Code", "dccp.reset_code", FT_UINT8, BASE_DEC, VALS(dccp_reset_code_vals), 0x0,
1078 { "Data 1", "dccp.data1", FT_UINT8, BASE_DEC, NULL, 0x0,
1082 { "Data 2", "dccp.data2", FT_UINT8, BASE_DEC, NULL, 0x0,
1086 { "Data 3", "dccp.data3", FT_UINT8, BASE_DEC, NULL, 0x0,
1089 { &hf_dccp_option_type,
1090 { "Option Type", "dccp.option_type", FT_UINT8, BASE_DEC, NULL, 0x0,
1093 { &hf_dccp_feature_number,
1094 { "Feature Number", "dccp.feature_number", FT_UINT8, BASE_DEC, NULL, 0x0,
1097 { &hf_dccp_ndp_count,
1098 { "NDP Count", "dccp.ndp_count", FT_UINT64, BASE_DEC, NULL, 0x0,
1101 { &hf_dccp_timestamp,
1102 { "Timestamp", "dccp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
1105 { &hf_dccp_timestamp_echo,
1106 { "Timestamp Echo", "dccp.timestamp_echo", FT_UINT32, BASE_DEC, NULL, 0x0,
1109 { &hf_dccp_elapsed_time,
1110 { "Elapsed Time", "dccp.elapsed_time", FT_UINT32, BASE_DEC, NULL, 0x0,
1113 { &hf_dccp_data_checksum,
1114 { "Data Checksum", "dccp.checksum_data", FT_UINT32, BASE_HEX, NULL, 0x0,
1117 { &hf_dccp_malformed,
1118 { "Malformed", "dccp.malformed", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1122 { "Options", "dccp.options", FT_NONE, BASE_NONE, NULL, 0x0,
1123 "DCCP Options fields", HFILL }}
1127 static gint *ett[] = {
1132 proto_dccp = proto_register_protocol("Datagram Congestion Control Protocol", "DCCP", "dccp");
1133 proto_register_field_array(proto_dccp, hf, array_length(hf));
1134 proto_register_subtree_array(ett, array_length(ett));
1137 dccp_subdissector_table = register_dissector_table("dccp.port", "DCCP port", FT_UINT16, BASE_DEC);
1138 register_heur_dissector_list("dccp", &heur_subdissector_list);
1140 /* reg preferences */
1141 dccp_module = prefs_register_protocol(proto_dccp, NULL);
1142 prefs_register_bool_preference(dccp_module, "summary_in_tree",
1143 "Show DCCP summary in protocol tree",
1144 "Whether the DCCP summary line should be shown in the protocol tree",
1145 &dccp_summary_in_tree);
1147 prefs_register_bool_preference(dccp_module, "try_heuristic_first",
1148 "Try heuristic sub-dissectors first",
1149 "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector "
1150 "registered to a specific port",
1151 &try_heuristic_first);
1153 prefs_register_bool_preference(dccp_module, "check_checksum",
1154 "Check the validity of the DCCP checksum when possible",
1155 "Whether to check the validity of the DCCP checksum",
1156 &dccp_check_checksum);
1159 void proto_reg_handoff_dccp(void)
1161 dissector_handle_t dccp_handle;
1163 dccp_handle = create_dissector_handle(dissect_dccp, proto_dccp);
1164 dissector_add("ip.proto", IP_PROTO_DCCP, dccp_handle);
1165 data_handle = find_dissector("data");
1166 dccp_tap = register_tap("dccp");