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 * PROTOABBREV name collision problem, 'dccp' is used by
36 * Distributed Checksum Clearinghouse Protocol.
37 * This dissector should be named packet-dccp.c IMHO.
39 * Nov 13, 2006: makes checksum computation dependent
40 * upon the header CsCov field (cf. RFC 4340, 5.1)
43 * Nov 13, 2006: removes the case where checksums are zero
44 * (unlike UDP/packet-udp, from which the code stems,
45 * zero checksums are illegal in DCCP (as in TCP))
48 * Jan 29, 2007: updates the offsets of the timestamps to be
49 * compliant to (cf. RFC 4342, sec. 13).
62 #include <epan/packet.h>
63 #include <epan/addr_resolv.h>
64 #include <epan/ipproto.h>
65 #include <epan/in_cksum.h>
66 #include <epan/prefs.h>
67 #include <epan/emem.h>
69 #include "packet-dcp.h"
71 #include "packet-ip.h"
72 #include <epan/conversation.h>
75 /* Some definitions and the dissect_options() logic have been taken from Arnaldo Carvalho de Melo's DCCP implementation, thanks! */
77 #define DCCP_HDR_LEN 16 /* base DCCP header length, with 48 bits seqnos */
78 #define DCCP_HDR_LEN_MIN 12 /* , with 24 bits seqnum */
79 #define DCCP_HDR_PKT_TYPES_LEN_MAX 12 /* max per packet type extra header length */
80 #define DCCP_OPT_LEN_MAX 1008
81 #define DCCP_HDR_LEN_MAX (DCCP_HDR_LEN + DCCP_HDR_PKT_TYPES_LEN_MAX + DCCP_OPT_LEN_MAX)
84 static const value_string dcp_packet_type_vals[] = {
104 static const value_string dcp_reset_code_vals[] = {
105 {0x00, "Unspecified"},
108 {0x03, "No Connection"},
109 {0x04, "Packet Error"},
110 {0x05, "Option Error"},
111 {0x06, "Mandatory Error"},
112 {0x07, "Connection Refused"},
113 {0x08, "Bad Service Code"},
115 {0x0A, "Bad Init Cookie"},
116 {0x0B, "Aggression Penalty"},
121 static const value_string dcp_feature_options_vals[] = {
129 static const value_string dcp_feature_numbers_vals[] = {
131 {0x02, "Allow Short Seqnos"},
132 {0x03, "Sequence Window"},
133 {0x04, "ECN Incapable"},
135 {0x06, "Send Ack Vector"},
136 {0x07, "Send NDP Count"},
137 {0x08, "Minimum Checksum Coverage"},
138 {0x09, "Check Data Checksum"},
139 {0xC0, "Send Loss Event Rate"}, /* CCID3, RFC 4342, 8.5 */
145 #define DBG(str, args...) do {\
152 fprintf(stdout, str, ## args); \
156 #define DBG1(format, arg1)
157 #define DBG2(format, arg1, arg2)
161 static int proto_dcp = -1;
162 static int dccp_tap = -1;
164 static int hf_dcp_srcport = -1;
165 static int hf_dcp_dstport = -1;
166 static int hf_dcp_port = -1;
167 static int hf_dcp_data_offset = -1;
168 static int hf_dcp_ccval = -1;
169 static int hf_dcp_cscov = -1;
170 static int hf_dcp_checksum = -1;
171 static int hf_dcp_checksum_bad = -1;
172 static int hf_dcp_res1 = -1;
173 static int hf_dcp_type = -1;
174 static int hf_dcp_x = -1;
175 static int hf_dcp_res2 = -1;
176 static int hf_dcp_seq = -1;
178 static int hf_dcp_ack_res = -1;
179 static int hf_dcp_ack = -1;
181 static int hf_dcp_service_code = -1;
182 static int hf_dcp_reset_code = -1;
183 static int hf_dcp_data1 = -1;
184 static int hf_dcp_data2 = -1;
185 static int hf_dcp_data3 = -1;
187 static int hf_dcp_options = -1;
188 static int hf_dcp_option_type = -1;
189 static int hf_dcp_feature_number = -1;
190 static int hf_dcp_ndp_count = -1;
191 static int hf_dcp_timestamp = -1;
192 static int hf_dcp_timestamp_echo = -1;
193 static int hf_dcp_elapsed_time = -1;
194 static int hf_dcp_data_checksum = -1;
196 static int hf_dcp_malformed = -1;
198 static gint ett_dcp = -1;
199 static gint ett_dcp_options = -1;
201 static dissector_table_t dcp_subdissector_table;
202 static heur_dissector_list_t heur_subdissector_list;
203 static dissector_handle_t data_handle;
206 static gboolean dcp_summary_in_tree = TRUE;
207 static gboolean try_heuristic_first = FALSE;
208 static gboolean dccp_check_checksum = TRUE;
212 decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int sport, int dport)
215 int low_port, high_port;
217 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
219 /* determine if this packet is part of a conversation and call dissector */
220 /* for the conversation if available */
222 if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_DCCP, sport, dport, next_tvb, pinfo, tree)) {
226 if (try_heuristic_first) {
227 /* do lookup with the heuristic subdissector table */
228 if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {
233 /* Do lookups with the subdissector table.
234 We try the port number with the lower value first, followed by the
235 port number with the higher value. This means that, for packets
236 where a dissector is registered for *both* port numbers:
238 1) we pick the same dissector for traffic going in both directions;
240 2) we prefer the port number that's more likely to be the right
241 one (as that prefers well-known ports to reserved ports);
243 although there is, of course, no guarantee that any such strategy
244 will always pick the right port number.
245 XXX - we ignore port numbers of 0, as some dissectors use a port
246 number of 0 to disable the port. */
256 dissector_try_port(dcp_subdissector_table, low_port, next_tvb, pinfo, tree)) {
259 if (high_port != 0 &&
260 dissector_try_port(dcp_subdissector_table, high_port, next_tvb, pinfo, tree)) {
264 if (!try_heuristic_first) {
265 /* do lookup with the heuristic subdissector table */
266 if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {
271 /* Oh, well, we don't know this; dissect it as data. */
272 call_dissector(data_handle, next_tvb, pinfo, tree);
276 * Auxiliary functions to dissect DCCP options
278 /* decode a variable-length number of nbytes starting at offset. Based on a concept by Arnaldo de Melo */
279 static guint64 tvb_get_ntoh_var(tvbuff_t *tvb, gint offset, guint nbytes)
284 ptr = tvb_get_ptr(tvb, offset, nbytes);
286 value += ((guint64)*ptr++) << 40;
288 value += ((guint64)*ptr++) << 32;
290 value += ((guint64)*ptr++) << 24;
292 value += ((guint64)*ptr++) << 16;
294 value += ((guint64)*ptr++) << 8;
301 static void dissect_feature_options(proto_tree *dcp_options_tree, tvbuff_t *tvb, int offset, guint8 option_len,
304 guint8 feature_number = tvb_get_guint8(tvb, offset + 2);
305 proto_item *dcp_item;
308 proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
310 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "%s(",
311 val_to_str(option_type, dcp_feature_options_vals, "Unknown Type"));
313 /* decode the feature according to whether it is server-priority (list) or NN (single number) */
314 switch (feature_number) {
315 /* Server Priority features (RFC 4340, 6.3.1) */
316 case 1: /* Congestion Control ID (CCID); fall through */
317 case 2: /* Allow Short Seqnos; fall through */
318 case 4: /* ECN Incapable; fall through */
319 case 6: /* Send Ack Vector; fall through */
320 case 7: /* Send NDP Count; fall through */
321 case 8: /* Minimum Checksum Coverage; fall through */
322 case 9: /* Check Data Checksum; fall through */
323 case 192: /* Send Loss Event Rate, RFC 4342, section 8.4 */
324 proto_item_append_text(dcp_item, "%s",
325 val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
326 for (i = 0; i < option_len - 3; i++)
327 proto_item_append_text(dcp_item, "%s %d", i? "," : "", tvb_get_guint8(tvb, offset + 3 + i));
329 /* Non-negotiable features (RFC 4340, 6.3.2) */
330 case 3: /* Sequence Window; fall through */
331 case 5: /* Ack Ratio */
332 proto_item_append_text(dcp_item, "%s",
333 val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
335 if (option_len > 3) /* could be empty Confirm */
336 proto_item_append_text(dcp_item, " %" G_GINT64_MODIFIER "u", tvb_get_ntoh_var(tvb, offset + 3, option_len - 3));
338 /* Reserved, specific, or unknown features */
340 if (feature_number == 0 ||
341 (feature_number >= 10 && feature_number <= 127))
342 proto_item_append_text(dcp_item, "Reserved feature number %d", feature_number);
343 else if (feature_number >= 193)
344 proto_item_append_text(dcp_item, "CCID-specific feature number %d", feature_number);
346 proto_item_append_text(dcp_item, "Unknown feature number %d", feature_number);
349 proto_item_append_text(dcp_item, ")");
353 * This function dissects DCCP options
355 static void dissect_options(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *dcp_options_tree, proto_tree *tree _U_, e_dcphdr *dcph _U_,
359 /* if here I'm sure there is at least offset_end - offset_start bytes in tvb and it should be options */
360 int offset=offset_start;
361 guint8 option_type = 0;
362 guint8 option_len = 0;
365 proto_item *dcp_item = NULL;
367 while( offset < offset_end ) {
369 /* DBG("offset==%d\n", offset); */
371 /* first byte is the option type */
372 option_type = tvb_get_guint8(tvb, offset);
373 proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_option_type, tvb, offset, 1, option_type);
375 if (option_type >= 32) { /* variable length options */
377 if(!tvb_bytes_exist(tvb, offset, 1)) {
378 /* DBG("malformed\n"); */
379 proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
380 THROW(ReportedBoundsError);
383 option_len = tvb_get_guint8(tvb, offset + 1);
385 if (option_len < 2) {
386 /* DBG("malformed\n"); */
387 proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
388 THROW(ReportedBoundsError);
391 if(!tvb_bytes_exist(tvb, offset, option_len)) {
392 /* DBG("malformed\n"); */
393 proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
394 THROW(ReportedBoundsError);
397 } else { /* 1byte options */
401 switch (option_type) {
404 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Padding");
408 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Mandatory");
412 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Slow Receiver");
419 dissect_feature_options(dcp_options_tree, tvb, offset, option_len, option_type);
423 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Init Cookie(");
424 for (i = 0; i < option_len - 2; i++) {
426 proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
428 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
430 proto_item_append_text(dcp_item, ")");
435 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count too long (max 6 bytes)");
437 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count: %" G_GINT64_MODIFIER "u",
438 tvb_get_ntoh_var(tvb, offset + 2, option_len - 2));
442 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector [Nonce 0]:");
443 for (i = 0; i < option_len - 2; i++)
444 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
448 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector [Nonce 1]:");
449 for (i = 0; i < option_len - 2; i++)
450 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
451 proto_item_append_text(dcp_item, ")");
455 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Data Dropped:");
456 for (i = 0; i < option_len - 2; i++)
457 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
462 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp, tvb, offset + 2, 4,
463 tvb_get_ntohl(tvb, offset + 2));
465 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
466 "Timestamp too long [%u != 6]", option_len);
471 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4,
472 tvb_get_ntohl(tvb, offset + 2));
473 else if (option_len==8) {
474 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4,
475 tvb_get_ntohl(tvb, offset + 2));
477 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 6, 2,
478 tvb_get_ntohs(tvb, offset + 6));
479 } else if (option_len==10) {
480 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4,
481 tvb_get_ntohl(tvb, offset + 2));
483 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 6, 4,
484 tvb_get_ntohl(tvb, offset + 6));
486 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Timestamp Echo length");
491 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 2, 2,
492 tvb_get_ntohs(tvb, offset + 2));
493 else if (option_len==6)
494 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 2, 4,
495 tvb_get_ntohl(tvb, offset + 2));
497 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Elapsed Time length");
502 proto_tree_add_uint(dcp_options_tree, hf_dcp_data_checksum, tvb, offset + 2, 4,
503 tvb_get_ntohl(tvb, offset + 2));
505 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Data checksum length");
507 case 192: /* RFC 4342, 8.5 */
508 if(option_len == 6) {
509 p = tvb_get_ntohl(tvb, offset + 2);
510 /* According to the comment in section 8.5 of RFC 4342, 0xffffffff can mean zero */
512 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: 0 (or max)");
514 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: %u", p);
516 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong CCID3 Loss Event Rate length");
518 case 193: /* RFC 4342, 8.6 */
519 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Intervals");
520 /* FIXME: not implemented and apparently not used by any implementation so far */
522 case 194: /* RFC 4342, 8.3 */
524 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Receive Rate: %u bytes/sec",
525 tvb_get_ntohl(tvb, offset + 2));
527 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong CCID3 Receive Rate length");
530 if(((option_type >= 45) && (option_type <= 127)) ||
531 ((option_type >= 3) && (option_type <= 31))) {
532 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Reserved");
536 if (option_type >= 128) {
537 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID option %d", option_type);
541 /* if here we don't know this option */
542 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Unknown");
547 offset+=option_len; /* Skip over the dissected option */
551 /* compute DCCP checksum coverage according to RFC 4340, section 9 */
552 static inline guint dccp_csum_coverage(const e_dcphdr *dcph, guint len)
556 if (dcph->cscov == 0)
558 cov = (dcph->data_offset + dcph->cscov - 1) * sizeof(guint32);
559 return (cov > len)? len : cov;
562 static void dissect_dcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
564 proto_tree *dcp_tree = NULL;
565 proto_tree *dcp_options_tree = NULL;
566 proto_item *dcp_item = NULL;
570 guint16 computed_cksum;
573 guint reported_len = 0;
574 guint advertised_dccp_header_len = 0;
575 guint options_len = 0;
578 /* get at least a full message header */
579 if(tvb_length(tvb) < DCCP_HDR_LEN_MIN) {
580 /* DBG("malformed\n"); */
582 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
583 if (check_col(pinfo->cinfo, COL_INFO))
584 col_set_str(pinfo->cinfo, COL_INFO, "Packet too short");
585 THROW(ReportedBoundsError);
588 dcph=ep_alloc(sizeof(e_dcphdr));
590 memset(dcph, 0, sizeof(e_dcphdr));
592 SET_ADDRESS(&dcph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
593 SET_ADDRESS(&dcph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
595 if (check_col(pinfo->cinfo, COL_PROTOCOL))
596 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCCP");
597 if (check_col(pinfo->cinfo, COL_INFO))
598 col_clear(pinfo->cinfo, COL_INFO);
600 /* Extract generic header */
601 dcph->sport=tvb_get_ntohs(tvb, offset);
602 /* DBG("dcph->sport: %d\n", dcph->sport); */
603 dcph->dport=tvb_get_ntohs(tvb, offset+2);
604 /* DBG("dcph->dport: %d\n", dcph->dport); */
606 /* update pinfo structure. I guess I have to do it, because this is a transport protocol dissector. Right? */
607 pinfo->ptype=PT_DCCP;
608 pinfo->srcport=dcph->sport;
609 pinfo->destport=dcph->dport;
611 dcph->data_offset=tvb_get_guint8(tvb, offset+4);
612 /* DBG("dcph->data_offset: %d\n", dcph->data_offset); */
613 dcph->cscov=tvb_get_guint8(tvb, offset+5)&0x0F;
614 /* DBG("dcph->cscov: %d\n", dcph->cscov); */
615 dcph->ccval=tvb_get_guint8(tvb, offset+5) &0xF0;
617 /* DBG("dcph->ccval: %d\n", dcph->ccval); */
618 dcph->checksum=tvb_get_ntohs(tvb, offset+6);
619 /* DBG("dcph->checksum: %d\n", dcph->checksum); */
620 dcph->reserved1=tvb_get_guint8(tvb, offset+8)&0xE0;
622 /* DBG("dcph->reserved1: %d\n", dcph->reserved1); */
623 dcph->type=tvb_get_guint8(tvb, offset+8)&0x1E;
625 /* DBG("dcph->type: %d\n", dcph->type); */
626 dcph->x=tvb_get_guint8(tvb, offset+8)&0x01;
627 /* DBG("dcph->x: %d\n", dcph->x); */
629 if(tvb_length(tvb) < DCCP_HDR_LEN) { /* at least 16 bytes */
630 /* DBG("malformed\n"); */
631 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
632 THROW(ReportedBoundsError);
634 dcph->reserved2=tvb_get_guint8(tvb, offset+9);
635 /* DBG("dcph->reserved2: %u\n", dcph->reserved2); */
636 dcph->seq=tvb_get_ntohs(tvb, offset+10);
638 dcph->seq+=tvb_get_ntohl(tvb, offset+12);
639 /* DBG("dcph->seq[48bits]: %" G_GINT64_MODIFIER "u\n", dcph->seq); */
641 dcph->seq=tvb_get_guint8(tvb, offset+9);
643 dcph->seq+=tvb_get_ntohs(tvb, offset+10);
644 /* DBG("dcph->seq[24bits]: %" G_GINT64_MODIFIER "u\n", dcph->seq); */
647 if (check_col(pinfo->cinfo, COL_INFO))
648 col_add_fstr(pinfo->cinfo, COL_INFO, "%s > %s [%s] Seq=%" G_GINT64_MODIFIER "u",
649 get_dccp_port(dcph->sport),
650 get_dccp_port(dcph->dport),
651 val_to_str(dcph->type, dcp_packet_type_vals, "Unknown Type"),
656 if(dcp_summary_in_tree) {
658 proto_tree_add_protocol_format(tree, proto_dcp, tvb, offset, dcph->data_offset*4,
659 "Datagram Congestion Control Protocol, Src Port: %s (%u), Dst Port: %s (%u)"
660 " [%s] Seq=%" G_GINT64_MODIFIER "u",
661 get_dccp_port(dcph->sport), dcph->sport,
662 get_dccp_port(dcph->dport), dcph->dport,
663 val_to_str(dcph->type, dcp_packet_type_vals, "Unknown Type"),
666 dcp_item = proto_tree_add_item(tree, proto_dcp, tvb, offset, 8, FALSE);
669 dcp_tree = proto_item_add_subtree(dcp_item, ett_dcp);
671 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_srcport, tvb, offset, 2, dcph->sport,
672 "%s (%u)", get_dccp_port(dcph->sport), dcph->sport);
673 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_dstport, tvb, offset + 2, 2, dcph->dport,
674 "%s (%u)", get_dccp_port(dcph->dport), dcph->dport);
676 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset, 2, dcph->sport);
677 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset + 2, 2, dcph->dport);
679 proto_tree_add_uint(dcp_tree, hf_dcp_data_offset, tvb, offset + 4, 1, dcph->data_offset);
680 proto_tree_add_uint(dcp_tree, hf_dcp_ccval, tvb, offset + 5, 1, dcph->ccval);
681 proto_tree_add_uint(dcp_tree, hf_dcp_cscov, tvb, offset + 5, 1, dcph->cscov);
683 /* checksum analysis taken from packet-udp (difference: mandatory checksums in DCCP) */
685 reported_len = tvb_reported_length(tvb);
686 len = tvb_length(tvb);
687 if (!pinfo->fragmented && len >= reported_len) {
689 /* The packet isn't part of a fragmented datagram and isn't
690 truncated, so we can checksum it.
691 XXX - make a bigger scatter-gather list once we do fragment
694 if (dccp_check_checksum) {
696 /* Set up the fields of the pseudo-header. */
697 cksum_vec[0].ptr = pinfo->src.data;
698 cksum_vec[0].len = pinfo->src.len;
699 cksum_vec[1].ptr = pinfo->dst.data;
700 cksum_vec[1].len = pinfo->dst.len;
701 cksum_vec[2].ptr = (const guint8 *)&phdr;
702 switch (pinfo->src.type) {
705 phdr[0] = g_htonl((IP_PROTO_DCCP<<16) + reported_len);
706 cksum_vec[2].len = 4;
709 phdr[0] = g_htonl(reported_len);
710 phdr[1] = g_htonl(IP_PROTO_DCCP);
711 cksum_vec[2].len = 8;
715 /* DCCP runs only atop IPv4 and IPv6.... */
716 /*DISSECTOR_ASSERT_NOT_REACHED();*/
719 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len);
720 cksum_vec[3].len = dccp_csum_coverage(dcph, reported_len);
721 computed_cksum = in_cksum(&cksum_vec[0], 4);
722 if (computed_cksum == 0) {
723 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
724 offset + 6, 2, dcph->checksum,
725 "0x%04x [correct]", dcph->checksum);
727 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_checksum_bad, tvb, offset + 6, 2, TRUE);
728 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb, offset + 6, 2, dcph->checksum,
729 "0x%04x [incorrect, should be 0x%04x]", dcph->checksum,
730 in_cksum_shouldbe(dcph->checksum, computed_cksum));
733 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
734 offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
737 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
738 offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
741 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_res1, tvb, offset + 8, 1, dcph->reserved1);
742 proto_tree_add_uint(dcp_tree, hf_dcp_type, tvb, offset + 8, 1, dcph->type);
743 proto_tree_add_boolean(dcp_tree, hf_dcp_x, tvb, offset + 8, 1, dcph->x);
745 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_res2, tvb, offset + 9, 1, dcph->reserved2);
746 proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 10, 6, dcph->seq);
748 proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 9, 3, dcph->seq);
754 offset+=16; /* Skip over extended Generic header */
756 offset+=12; /* Skip over not extended Generic header */
758 /* dissecting type depending additional fields */
761 case 0x0: /* DCCP-Request */
762 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
764 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
767 dcph->service_code=tvb_get_ntohl(tvb, offset);
769 proto_tree_add_uint(dcp_tree, hf_dcp_service_code, tvb, offset, 4, dcph->service_code);
770 if (check_col(pinfo->cinfo, COL_INFO))
771 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dcph->service_code);
773 offset+=4; /* Skip over service code */
776 case 0x1: /* DCCP-Response */
777 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
779 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
782 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
784 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
785 dcph->ack=tvb_get_ntohs(tvb, offset+2);
787 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
790 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
791 if (check_col(pinfo->cinfo, COL_INFO))
792 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
794 offset+=8; /* Skip over Acknowledgement Number Subheader */
796 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
798 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
801 dcph->service_code=tvb_get_ntohl(tvb, offset);
803 proto_tree_add_uint(dcp_tree, hf_dcp_service_code, tvb, offset, 4, dcph->service_code);
804 if (check_col(pinfo->cinfo, COL_INFO))
805 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dcph->service_code);
807 offset+=4; /* Skip over service code */
810 case 0x2: /* DCCP-Data */
811 /* nothing to dissect */
814 case 0x3: /* DCCP-Ack */
815 case 0x4: /* DCCP-DataAck */
817 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
819 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
822 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
824 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
825 dcph->ack=tvb_get_ntohs(tvb, offset+2);
827 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
829 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
830 if (check_col(pinfo->cinfo, COL_INFO))
831 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
833 offset+=8; /* Skip over Acknowledgement Number Subheader */
835 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
837 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
840 dcph->ack_reserved=tvb_get_guint8(tvb, offset);
842 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 1, dcph->ack_reserved);
843 dcph->ack=tvb_get_guint8(tvb, offset+1);
845 dcph->ack+=tvb_get_ntohs(tvb, offset+2);
847 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 1, 3, dcph->ack);
848 if (check_col(pinfo->cinfo, COL_INFO))
849 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
851 offset+=4; /* Skip over Acknowledgement Number Subheader */
855 case 0x7: /* DCCP-Reset */
856 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
858 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
861 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
863 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
864 dcph->ack=tvb_get_ntohs(tvb, offset+2);
866 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
868 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
869 if (check_col(pinfo->cinfo, COL_INFO))
870 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
872 offset+=8; /* Skip over Acknowledgement Number Subheader */
874 dcph->reset_code=tvb_get_guint8(tvb, offset);
875 dcph->data1=tvb_get_guint8(tvb, offset+1);
876 dcph->data2=tvb_get_guint8(tvb, offset+2);
877 dcph->data3=tvb_get_guint8(tvb, offset+3);
879 proto_tree_add_uint(dcp_tree, hf_dcp_reset_code, tvb, offset, 1, dcph->reset_code);
880 proto_tree_add_uint(dcp_tree, hf_dcp_data1, tvb, offset + 1, 1, dcph->data1);
881 proto_tree_add_uint(dcp_tree, hf_dcp_data2, tvb, offset + 2, 1, dcph->data2);
882 proto_tree_add_uint(dcp_tree, hf_dcp_data3, tvb, offset + 3, 1, dcph->data3);
884 if (check_col(pinfo->cinfo, COL_INFO))
885 col_append_fstr(pinfo->cinfo, COL_INFO, " (code=%s)", val_to_str(dcph->reset_code, dcp_reset_code_vals, "Unknown"));
887 offset+=4; /* Skip over Reset Code and data123 */
890 case 0x5: /* DCCP-CloseReq */
891 case 0x6: /* DCCP-Close */
892 case 0x8: /* DCCP-Sync */
893 case 0x9: /* DCCP-SyncAck */
894 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
896 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
899 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
901 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
902 dcph->ack=tvb_get_ntohs(tvb, offset+2);
904 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
906 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
907 if (check_col(pinfo->cinfo, COL_INFO))
908 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
910 offset+=8; /* Skip over Acknowledgement Number Subheader */
915 proto_tree_add_text(dcp_tree, tvb, offset, -1, "Reserved packet type: unable to dissect further");
921 /* note: data_offset is the offset from the start of the packet's DCCP header to the
922 * start of its application data area, in 32-bit words.
925 /* it's time to do some checks */
926 advertised_dccp_header_len = dcph->data_offset*4;
927 options_len = advertised_dccp_header_len - offset;
929 if ( advertised_dccp_header_len > DCCP_HDR_LEN_MAX ) {
931 proto_tree_add_text(dcp_tree, tvb, 4, 2,
932 "bogus data offset, advertised header length (%d) is larger than max (%d)",
933 advertised_dccp_header_len, DCCP_HDR_LEN_MAX);
937 if(tvb_length(tvb) < advertised_dccp_header_len) {
939 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet: missing %d bytes of DCCP header",
940 advertised_dccp_header_len - tvb_reported_length_remaining(tvb, offset));
944 if(options_len > DCCP_OPT_LEN_MAX) {
945 /* DBG("malformed\n"); */
947 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
948 THROW(ReportedBoundsError);
952 /* Dissecting Options (if here we have at least (advertised_dccp_header_len - offset) bytes of options) */
953 if(advertised_dccp_header_len == offset) {
954 ; /* ok no options, no need to skip over */
955 } else if (advertised_dccp_header_len < offset) {
957 proto_tree_add_text(dcp_tree, tvb, 4, 2,
958 "bogus data offset, advertised header length (%d) is shorter than expected",
959 advertised_dccp_header_len);
960 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
962 THROW(ReportedBoundsError);
965 dcp_item = proto_tree_add_none_format(dcp_tree, hf_dcp_options, tvb, offset, options_len, "Options: (%u bytes)", options_len);
966 dcp_options_tree = proto_item_add_subtree(dcp_item, ett_dcp_options);
968 dissect_options(tvb, pinfo, dcp_options_tree, tree, dcph, offset, offset + options_len);
971 offset+=options_len; /* Skip over Options */
973 /* Queuing tap data */
974 tap_queue_packet(dccp_tap, pinfo, dcph);
976 /* Call sub-dissectors */
978 if (!pinfo->in_error_pkt || tvb_length_remaining(tvb, offset) > 0)
979 decode_dccp_ports(tvb, offset, pinfo, tree, dcph->sport, dcph->dport);
983 void proto_register_dcp(void)
985 module_t *dcp_module;
987 static hf_register_info hf[] = {
989 { "Source Port", "dcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
993 { "Destination Port", "dcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
997 { "Source or Destination Port", "dcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
1000 { &hf_dcp_data_offset,
1001 { "Data Offset", "dcp.data_offset", FT_UINT8, BASE_DEC, NULL, 0x0,
1005 { "CCVal", "dcp.ccval", FT_UINT8, BASE_DEC, NULL, 0x0,
1009 { "Checksum Coverage", "dcp.cscov", FT_UINT8, BASE_DEC, NULL, 0x0,
1012 { &hf_dcp_checksum_bad,
1013 { "Bad Checksum", "dcp.checksum_bad", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1017 { "Checksum", "dcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1021 { "Reserved", "dcp.res1", FT_UINT8, BASE_HEX, NULL, 0x0,
1025 { "Reserved", "dcp.res2", FT_UINT8, BASE_HEX, NULL, 0x0,
1029 { "Type", "dcp.type", FT_UINT8, BASE_DEC, VALS(dcp_packet_type_vals), 0x0,
1033 { "Extended Sequence Numbers", "dcp.x", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1037 { "Sequence Number", "dcp.seq", FT_UINT64, BASE_DEC, NULL, 0x0,
1041 { "Reserved", "dcp.ack_res", FT_UINT16, BASE_HEX, NULL, 0x0,
1045 { "Acknowledgement Number", "dcp.ack", FT_UINT64, BASE_DEC, NULL, 0x0,
1048 { &hf_dcp_service_code,
1049 { "Service Code", "dcp.service_code", FT_UINT32, BASE_DEC, NULL, 0x0,
1052 { &hf_dcp_reset_code,
1053 { "Reset Code", "dcp.reset_code", FT_UINT8, BASE_DEC, VALS(dcp_reset_code_vals), 0x0,
1057 { "Data 1", "dcp.data1", FT_UINT8, BASE_DEC, NULL, 0x0,
1061 { "Data 2", "dcp.data2", FT_UINT8, BASE_DEC, NULL, 0x0,
1065 { "Data 3", "dcp.data3", FT_UINT8, BASE_DEC, NULL, 0x0,
1068 { &hf_dcp_option_type,
1069 { "Option Type", "dcp.option_type", FT_UINT8, BASE_DEC, NULL, 0x0,
1072 { &hf_dcp_feature_number,
1073 { "Feature Number", "dcp.feature_number", FT_UINT8, BASE_DEC, NULL, 0x0,
1076 { &hf_dcp_ndp_count,
1077 { "NDP Count", "dcp.ndp_count", FT_UINT64, BASE_DEC, NULL, 0x0,
1080 { &hf_dcp_timestamp,
1081 { "Timestamp", "dcp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
1084 { &hf_dcp_timestamp_echo,
1085 { "Timestamp Echo", "dcp.timestamp_echo", FT_UINT32, BASE_DEC, NULL, 0x0,
1088 { &hf_dcp_elapsed_time,
1089 { "Elapsed Time", "dcp.elapsed_time", FT_UINT32, BASE_DEC, NULL, 0x0,
1092 { &hf_dcp_data_checksum,
1093 { "Data Checksum", "dcp.checksum_data", FT_UINT32, BASE_HEX, NULL, 0x0,
1096 { &hf_dcp_malformed,
1097 { "Malformed", "dcp.malformed", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1101 { "Options", "dcp.options", FT_NONE, BASE_DEC, NULL, 0x0,
1102 "DCP Options fields", HFILL }}
1106 static gint *ett[] = {
1111 proto_dcp = proto_register_protocol("Datagram Congestion Control Protocol", "DCP", "dcp");
1112 proto_register_field_array(proto_dcp, hf, array_length(hf));
1113 proto_register_subtree_array(ett, array_length(ett));
1116 dcp_subdissector_table = register_dissector_table("dcp.port", "DCP port", FT_UINT16, BASE_DEC);
1117 register_heur_dissector_list("dcp", &heur_subdissector_list);
1119 /* reg preferences */
1120 dcp_module = prefs_register_protocol(proto_dcp, NULL);
1121 prefs_register_bool_preference(dcp_module, "summary_in_tree",
1122 "Show DCCP summary in protocol tree",
1123 "Whether the DCCP summary line should be shown in the protocol tree",
1124 &dcp_summary_in_tree);
1126 prefs_register_bool_preference(dcp_module, "try_heuristic_first",
1127 "Try heuristic sub-dissectors first",
1128 "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector "
1129 "registered to a specific port",
1130 &try_heuristic_first);
1132 prefs_register_bool_preference(dcp_module, "check_checksum",
1133 "Check the validity of the DCCP checksum when possible",
1134 "Whether to check the validity of the DCCP checksum",
1135 &dccp_check_checksum);
1138 void proto_reg_handoff_dcp(void)
1140 dissector_handle_t dcp_handle;
1142 dcp_handle = create_dissector_handle(dissect_dcp, proto_dcp);
1143 dissector_add("ip.proto", IP_PROTO_DCCP, dcp_handle);
1144 data_handle = find_dissector("data");
1145 dccp_tap = register_tap("dccp");