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_numbers_vals[] = {
123 {0x02, "Allow Short Seqnos"},
124 {0x03, "Sequence Window"},
125 {0x04, "ECN Incapable"},
127 {0x06, "Send Ack Vector"},
128 {0x07, "Send NDP Count"},
129 {0x08, "Minimum Checksum Coverage"},
130 {0x09, "Check Data Checksum"},
136 #define DBG(str, args...) do {\
143 fprintf(stdout, str, ## args); \
147 #define DBG1(format, arg1)
148 #define DBG2(format, arg1, arg2)
152 static int proto_dcp = -1;
153 static int dccp_tap = -1;
155 static int hf_dcp_srcport = -1;
156 static int hf_dcp_dstport = -1;
157 static int hf_dcp_port = -1;
158 static int hf_dcp_data_offset = -1;
159 static int hf_dcp_ccval = -1;
160 static int hf_dcp_cscov = -1;
161 static int hf_dcp_checksum = -1;
162 static int hf_dcp_checksum_bad = -1;
163 static int hf_dcp_res1 = -1;
164 static int hf_dcp_type = -1;
165 static int hf_dcp_x = -1;
166 static int hf_dcp_res2 = -1;
167 static int hf_dcp_seq = -1;
169 static int hf_dcp_ack_res = -1;
170 static int hf_dcp_ack = -1;
172 static int hf_dcp_service_code = -1;
173 static int hf_dcp_reset_code = -1;
174 static int hf_dcp_data1 = -1;
175 static int hf_dcp_data2 = -1;
176 static int hf_dcp_data3 = -1;
178 static int hf_dcp_options = -1;
179 static int hf_dcp_option_type = -1;
180 static int hf_dcp_feature_number = -1;
181 static int hf_dcp_ndp_count = -1;
182 static int hf_dcp_timestamp = -1;
183 static int hf_dcp_timestamp_echo = -1;
184 static int hf_dcp_elapsed_time = -1;
185 static int hf_dcp_data_checksum = -1;
187 static int hf_dcp_malformed = -1;
189 static gint ett_dcp = -1;
190 static gint ett_dcp_options = -1;
192 static dissector_table_t dcp_subdissector_table;
193 static heur_dissector_list_t heur_subdissector_list;
194 static dissector_handle_t data_handle;
197 static gboolean dcp_summary_in_tree = TRUE;
198 static gboolean try_heuristic_first = FALSE;
199 static gboolean dccp_check_checksum = TRUE;
203 decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int sport, int dport)
206 int low_port, high_port;
208 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
210 /* determine if this packet is part of a conversation and call dissector */
211 /* for the conversation if available */
213 if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_DCCP, sport, dport, next_tvb, pinfo, tree)) {
217 if (try_heuristic_first) {
218 /* do lookup with the heuristic subdissector table */
219 if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {
224 /* Do lookups with the subdissector table.
225 We try the port number with the lower value first, followed by the
226 port number with the higher value. This means that, for packets
227 where a dissector is registered for *both* port numbers:
229 1) we pick the same dissector for traffic going in both directions;
231 2) we prefer the port number that's more likely to be the right
232 one (as that prefers well-known ports to reserved ports);
234 although there is, of course, no guarantee that any such strategy
235 will always pick the right port number.
236 XXX - we ignore port numbers of 0, as some dissectors use a port
237 number of 0 to disable the port. */
247 dissector_try_port(dcp_subdissector_table, low_port, next_tvb, pinfo, tree)) {
250 if (high_port != 0 &&
251 dissector_try_port(dcp_subdissector_table, high_port, next_tvb, pinfo, tree)) {
255 if (!try_heuristic_first) {
256 /* do lookup with the heuristic subdissector table */
257 if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) {
262 /* Oh, well, we don't know this; dissect it as data. */
263 call_dissector(data_handle, next_tvb, pinfo, tree);
268 * This function dissects DCCP options
270 static void dissect_options(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *dcp_options_tree, proto_tree *tree _U_, e_dcphdr *dcph _U_,
274 /* if here I'm sure there is at least offset_end - offset_start bytes in tvb and it should be options */
275 int offset=offset_start;
276 guint8 option_type = 0;
277 guint8 option_len = 0;
278 guint8 feature_number = 0;
280 proto_item *dcp_item = NULL;
282 while( offset < offset_end ) {
284 /* DBG("offset==%d\n", offset); */
286 /* first byte is the option type */
287 option_type = tvb_get_guint8(tvb, offset);
288 proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_option_type, tvb, offset, 1, option_type);
290 if (option_type >= 32) { /* variable length options */
292 if(!tvb_bytes_exist(tvb, offset, 1)) {
293 /* DBG("malformed\n"); */
294 proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
295 THROW(ReportedBoundsError);
298 option_len = tvb_get_guint8(tvb, offset + 1);
300 if (option_len < 2) {
301 /* DBG("malformed\n"); */
302 proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
303 THROW(ReportedBoundsError);
306 if(!tvb_bytes_exist(tvb, offset, option_len)) {
307 /* DBG("malformed\n"); */
308 proto_tree_add_boolean_hidden(dcp_options_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
309 THROW(ReportedBoundsError);
312 } else { /* 1byte options */
316 switch (option_type) {
319 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Padding");
323 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Mandatory");
327 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Slow Receiver");
331 feature_number = tvb_get_guint8(tvb, offset + 2);
332 proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
334 if( (feature_number < 10) && (feature_number!=0) ) {
335 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
337 val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
338 for (i = 0; i < option_len - 3; i++) {
340 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
342 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
344 proto_item_append_text(dcp_item, ")");
346 if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
347 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
348 "Change L(Reserved feature number)");
350 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
351 "Change L(CCID-specific features)");
356 feature_number = tvb_get_guint8(tvb, offset + 2);
357 proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
359 if( (feature_number < 10) && (feature_number!=0) ) {
360 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
362 val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
363 for (i = 0; i < option_len - 3; i++) {
365 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
367 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
369 proto_item_append_text(dcp_item, ")");
371 if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
372 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
373 "Confirm L(Reserved feature number)");
375 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
376 "Confirm L(CCID-specific features)");
381 feature_number = tvb_get_guint8(tvb, offset + 2);
382 proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
384 if( (feature_number < 10) && (feature_number!=0) ) {
385 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
387 val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
388 for (i = 0; i < option_len - 3; i++) {
390 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
392 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
394 proto_item_append_text(dcp_item, ")");
396 if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
397 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
398 "Change R(Reserved feature number)");
400 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
401 "Change R(CCID-specific features)");
406 feature_number = tvb_get_guint8(tvb, offset + 2);
407 proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
409 if( (feature_number < 10) && (feature_number!=0) ) {
410 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
412 val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
413 for (i = 0; i < option_len - 3; i++) {
415 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
417 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
419 proto_item_append_text(dcp_item, ")");
421 if(((feature_number>=10)&&(feature_number<=127))||(feature_number==0))
422 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
423 "Confirm R(Reserved feature number)");
425 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
426 "Confirm R(CCID-specific features)");
431 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Init Cookie(");
432 for (i = 0; i < option_len - 2; i++) {
434 proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
436 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
438 proto_item_append_text(dcp_item, ")");
443 proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 1,
444 tvb_get_guint8(tvb, offset + 2));
445 else if (option_len==4)
446 proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 2,
447 tvb_get_ntohs(tvb, offset + 2));
448 else if (option_len==5)
449 proto_tree_add_uint(dcp_options_tree, hf_dcp_ndp_count, tvb, offset + 2, 3,
450 tvb_get_ntoh24(tvb, offset + 2));
452 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count too long (max 3 bytes)");
457 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector0(");
458 for (i = 0; i < option_len - 2; i++) {
460 proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
462 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
464 proto_item_append_text(dcp_item, ")");
468 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Ack Vector1(");
469 for (i = 0; i < option_len - 2; i++) {
471 proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
473 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
475 proto_item_append_text(dcp_item, ")");
479 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Data Dropped(");
480 for (i = 0; i < option_len - 2; i++) {
482 proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
484 proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
486 proto_item_append_text(dcp_item, ")");
491 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp, tvb, offset + 2, 4,
492 tvb_get_ntohl(tvb, offset + 2));
494 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
495 "Timestamp too long [%u != 6]", option_len);
500 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4,
501 tvb_get_ntohl(tvb, offset + 2));
502 else if (option_len==8) {
503 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4,
504 tvb_get_ntohl(tvb, offset + 2));
506 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 6, 2,
507 tvb_get_ntohs(tvb, offset + 6));
508 } else if (option_len==10) {
509 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp_echo, tvb, offset + 2, 4,
510 tvb_get_ntohl(tvb, offset + 2));
512 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 6, 4,
513 tvb_get_ntohl(tvb, offset + 6));
515 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Timestamp Echo length");
520 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 2, 2,
521 tvb_get_ntohs(tvb, offset + 2));
522 else if (option_len==6)
523 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 2, 4,
524 tvb_get_ntohl(tvb, offset + 2));
526 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Elapsed Time length");
531 proto_tree_add_uint(dcp_options_tree, hf_dcp_data_checksum, tvb, offset + 2, 4,
532 tvb_get_ntohl(tvb, offset + 2));
534 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Data checksum length");
538 if(((option_type >= 45) && (option_type <= 127)) ||
539 ((option_type >= 3) && (option_type <= 31))) {
540 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Reserved");
544 if (option_type >= 128) {
545 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID option %d", option_type);
549 /* if here we don't know this option */
550 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Unknown");
555 offset+=option_len; /* Skip over the dissected option */
559 /* compute DCCP checksum coverage according to RFC 4340, section 9 */
560 static inline guint dccp_csum_coverage(const e_dcphdr *dcph, guint len)
564 if (dcph->cscov == 0)
566 cov = (dcph->data_offset + dcph->cscov - 1) * sizeof(guint32);
567 return (cov > len)? len : cov;
570 static void dissect_dcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
572 proto_tree *dcp_tree = NULL;
573 proto_tree *dcp_options_tree = NULL;
574 proto_item *dcp_item = NULL;
578 guint16 computed_cksum;
581 guint reported_len = 0;
582 guint advertised_dccp_header_len = 0;
583 guint options_len = 0;
586 /* get at least a full message header */
587 if(!tvb_bytes_exist(tvb, 0, DCCP_HDR_LEN_MIN)) {
588 /* DBG("malformed\n"); */
590 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
591 if (check_col(pinfo->cinfo, COL_INFO))
592 col_add_fstr(pinfo->cinfo, COL_INFO, "Packet too short");
593 THROW(ReportedBoundsError);
596 dcph=ep_alloc(sizeof(e_dcphdr));
598 memset(dcph, 0, sizeof(e_dcphdr));
600 SET_ADDRESS(&dcph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
601 SET_ADDRESS(&dcph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);
603 if (check_col(pinfo->cinfo, COL_PROTOCOL))
604 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCCP");
605 if (check_col(pinfo->cinfo, COL_INFO))
606 col_clear(pinfo->cinfo, COL_INFO);
608 /* Extract generic header */
609 dcph->sport=tvb_get_ntohs(tvb, offset);
610 /* DBG("dcph->sport: %d\n", dcph->sport); */
611 dcph->dport=tvb_get_ntohs(tvb, offset+2);
612 /* DBG("dcph->dport: %d\n", dcph->dport); */
614 /* update pinfo structure. I guess I have to do it, because this is a transport protocol dissector. Right? */
615 pinfo->ptype=PT_DCCP;
616 pinfo->srcport=dcph->sport;
617 pinfo->destport=dcph->dport;
619 dcph->data_offset=tvb_get_guint8(tvb, offset+4);
620 /* DBG("dcph->data_offset: %d\n", dcph->data_offset); */
621 dcph->cscov=tvb_get_guint8(tvb, offset+5)&0x0F;
622 /* DBG("dcph->cscov: %d\n", dcph->cscov); */
623 dcph->ccval=tvb_get_guint8(tvb, offset+5) &0xF0;
625 /* DBG("dcph->ccval: %d\n", dcph->ccval); */
626 dcph->checksum=tvb_get_ntohs(tvb, offset+6);
627 /* DBG("dcph->checksum: %d\n", dcph->checksum); */
628 dcph->reserved1=tvb_get_guint8(tvb, offset+8)&0xE0;
630 /* DBG("dcph->reserved1: %d\n", dcph->reserved1); */
631 dcph->type=tvb_get_guint8(tvb, offset+8)&0x1E;
633 /* DBG("dcph->type: %d\n", dcph->type); */
634 dcph->x=tvb_get_guint8(tvb, offset+8)&0x01;
635 /* DBG("dcph->x: %d\n", dcph->x); */
637 if(!tvb_bytes_exist(tvb, 0, DCCP_HDR_LEN)) { /* at least 16 bytes */
638 /* DBG("malformed\n"); */
639 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
640 THROW(ReportedBoundsError);
642 dcph->reserved2=tvb_get_guint8(tvb, offset+9);
643 /* DBG("dcph->reserved2: %u\n", dcph->reserved2); */
644 dcph->seq=tvb_get_ntohs(tvb, offset+10);
646 dcph->seq+=tvb_get_ntohl(tvb, offset+12);
647 /* DBG("dcph->seq[48bits]: %llu\n", dcph->seq); */
649 dcph->seq=tvb_get_guint8(tvb, offset+9);
651 dcph->seq+=tvb_get_ntohs(tvb, offset+10);
652 /* DBG("dcph->seq[24bits]: %llu\n", dcph->seq); */
655 if (check_col(pinfo->cinfo, COL_INFO))
656 col_add_fstr(pinfo->cinfo, COL_INFO, "%s > %s [%s] Seq=%" G_GINT64_MODIFIER "u",
657 get_dccp_port(dcph->sport),
658 get_dccp_port(dcph->dport),
659 val_to_str(dcph->type, dcp_packet_type_vals, "Unknown Type"),
664 if(dcp_summary_in_tree) {
666 proto_tree_add_protocol_format(tree, proto_dcp, tvb, offset, dcph->data_offset*4,
667 "Datagram Congestion Control Protocol, Src Port: %s (%u), Dst Port: %s (%u)"
668 " [%s] Seq=%" G_GINT64_MODIFIER "u",
669 get_dccp_port(dcph->sport), dcph->sport,
670 get_dccp_port(dcph->dport), dcph->dport,
671 val_to_str(dcph->type, dcp_packet_type_vals, "Unknown Type"),
674 dcp_item = proto_tree_add_item(tree, proto_dcp, tvb, offset, 8, FALSE);
677 dcp_tree = proto_item_add_subtree(dcp_item, ett_dcp);
679 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_srcport, tvb, offset, 2, dcph->sport,
680 "%s (%u)", get_dccp_port(dcph->sport), dcph->sport);
681 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_dstport, tvb, offset + 2, 2, dcph->dport,
682 "%s (%u)", get_dccp_port(dcph->dport), dcph->dport);
684 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset, 2, dcph->sport);
685 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_port, tvb, offset + 2, 2, dcph->dport);
687 proto_tree_add_uint(dcp_tree, hf_dcp_data_offset, tvb, offset + 4, 1, dcph->data_offset);
688 proto_tree_add_uint(dcp_tree, hf_dcp_ccval, tvb, offset + 5, 1, dcph->ccval);
689 proto_tree_add_uint(dcp_tree, hf_dcp_cscov, tvb, offset + 5, 1, dcph->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(dcph, reported_len);
729 computed_cksum = in_cksum(&cksum_vec[0], 4);
730 if (computed_cksum == 0) {
731 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
732 offset + 6, 2, dcph->checksum,
733 "0x%04x [correct]", dcph->checksum);
735 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_checksum_bad, tvb, offset + 6, 2, TRUE);
736 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb, offset + 6, 2, dcph->checksum,
737 "0x%04x [incorrect, should be 0x%04x]", dcph->checksum,
738 in_cksum_shouldbe(dcph->checksum, computed_cksum));
741 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
742 offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
745 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
746 offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
749 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_res1, tvb, offset + 8, 1, dcph->reserved1);
750 proto_tree_add_uint(dcp_tree, hf_dcp_type, tvb, offset + 8, 1, dcph->type);
751 proto_tree_add_boolean(dcp_tree, hf_dcp_x, tvb, offset + 8, 1, dcph->x);
753 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_res2, tvb, offset + 9, 1, dcph->reserved2);
754 proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 10, 6, dcph->seq);
756 proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 9, 3, dcph->seq);
762 offset+=16; /* Skip over extended Generic header */
764 offset+=12; /* Skip over not extended Generic header */
766 /* dissecting type depending additional fields */
769 case 0x0: /* DCCP-Request */
770 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
772 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
775 dcph->service_code=tvb_get_ntohl(tvb, offset);
777 proto_tree_add_uint(dcp_tree, hf_dcp_service_code, tvb, offset, 4, dcph->service_code);
778 if (check_col(pinfo->cinfo, COL_INFO))
779 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dcph->service_code);
781 offset+=4; /* Skip over service code */
784 case 0x1: /* DCCP-Response */
785 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
787 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
790 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
792 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
793 dcph->ack=tvb_get_ntohs(tvb, offset+2);
795 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
798 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
799 if (check_col(pinfo->cinfo, COL_INFO))
800 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
802 offset+=8; /* Skip over Acknowledgement Number Subheader */
804 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
806 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
809 dcph->service_code=tvb_get_ntohl(tvb, offset);
811 proto_tree_add_uint(dcp_tree, hf_dcp_service_code, tvb, offset, 4, dcph->service_code);
812 if (check_col(pinfo->cinfo, COL_INFO))
813 col_append_fstr(pinfo->cinfo, COL_INFO, " (service=%u)", dcph->service_code);
815 offset+=4; /* Skip over service code */
818 case 0x2: /* DCCP-Data */
819 /* nothing to dissect */
822 case 0x3: /* DCCP-Ack */
823 case 0x4: /* DCCP-DataAck */
825 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
827 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
830 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
832 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
833 dcph->ack=tvb_get_ntohs(tvb, offset+2);
835 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
837 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
838 if (check_col(pinfo->cinfo, COL_INFO))
839 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
841 offset+=8; /* Skip over Acknowledgement Number Subheader */
843 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
845 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
848 dcph->ack_reserved=tvb_get_guint8(tvb, offset);
850 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 1, dcph->ack_reserved);
851 dcph->ack=tvb_get_guint8(tvb, offset+1);
853 dcph->ack+=tvb_get_ntohs(tvb, offset+2);
855 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 1, 3, dcph->ack);
856 if (check_col(pinfo->cinfo, COL_INFO))
857 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
859 offset+=4; /* Skip over Acknowledgement Number Subheader */
863 case 0x7: /* DCCP-Reset */
864 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
866 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
869 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
871 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
872 dcph->ack=tvb_get_ntohs(tvb, offset+2);
874 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
876 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
877 if (check_col(pinfo->cinfo, COL_INFO))
878 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
880 offset+=8; /* Skip over Acknowledgement Number Subheader */
882 dcph->reset_code=tvb_get_guint8(tvb, offset);
883 dcph->data1=tvb_get_guint8(tvb, offset+1);
884 dcph->data2=tvb_get_guint8(tvb, offset+2);
885 dcph->data3=tvb_get_guint8(tvb, offset+3);
887 proto_tree_add_uint(dcp_tree, hf_dcp_reset_code, tvb, offset, 1, dcph->reset_code);
888 proto_tree_add_uint(dcp_tree, hf_dcp_data1, tvb, offset + 1, 1, dcph->data1);
889 proto_tree_add_uint(dcp_tree, hf_dcp_data2, tvb, offset + 2, 1, dcph->data2);
890 proto_tree_add_uint(dcp_tree, hf_dcp_data3, tvb, offset + 3, 1, dcph->data3);
892 if (check_col(pinfo->cinfo, COL_INFO))
893 col_append_fstr(pinfo->cinfo, COL_INFO, " (code=%s)", val_to_str(dcph->reset_code, dcp_reset_code_vals, "Unknown"));
895 offset+=4; /* Skip over Reset Code and data123 */
898 case 0x5: /* DCCP-CloseReq */
899 case 0x6: /* DCCP-Close */
900 case 0x8: /* DCCP-Sync */
901 case 0x9: /* DCCP-SyncAck */
902 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
904 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
907 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
909 proto_tree_add_uint_hidden(dcp_tree, hf_dcp_ack_res, tvb, offset, 2, dcph->ack_reserved);
910 dcph->ack=tvb_get_ntohs(tvb, offset+2);
912 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
914 proto_tree_add_uint64(dcp_tree, hf_dcp_ack, tvb, offset + 2, 6, dcph->ack);
915 if (check_col(pinfo->cinfo, COL_INFO))
916 col_append_fstr(pinfo->cinfo, COL_INFO, " (Ack=%" G_GINT64_MODIFIER "u)", dcph->ack);
918 offset+=8; /* Skip over Acknowledgement Number Subheader */
923 proto_tree_add_text(dcp_tree, tvb, offset, -1, "Reserved packet type: unable to dissect further");
929 /* note: data_offset is the offset from the start of the packet's DCCP header to the
930 * start of its application data area, in 32-bit words.
933 /* it's time to do some checks */
934 advertised_dccp_header_len = dcph->data_offset*4;
935 options_len = advertised_dccp_header_len - offset;
937 if ( advertised_dccp_header_len > DCCP_HDR_LEN_MAX ) {
939 proto_tree_add_text(dcp_tree, tvb, 4, 2,
940 "bogus data offset, advertised header length (%d) is larger than max (%d)",
941 advertised_dccp_header_len, DCCP_HDR_LEN_MAX);
945 if(!tvb_bytes_exist(tvb, 0, advertised_dccp_header_len)) {
947 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet: missing %d bytes of DCCP header",
948 advertised_dccp_header_len - tvb_reported_length_remaining(tvb, offset));
952 if(options_len > DCCP_OPT_LEN_MAX) {
953 /* DBG("malformed\n"); */
955 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
956 THROW(ReportedBoundsError);
960 /* Dissecting Options (if here we have at least (advertised_dccp_header_len - offset) bytes of options) */
961 if(advertised_dccp_header_len == offset) {
962 ; /* ok no options, no need to skip over */
963 } else if (advertised_dccp_header_len < offset) {
965 proto_tree_add_text(dcp_tree, tvb, 4, 2,
966 "bogus data offset, advertised header length (%d) is shorter than expected",
967 advertised_dccp_header_len);
968 proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
970 THROW(ReportedBoundsError);
973 dcp_item = proto_tree_add_none_format(dcp_tree, hf_dcp_options, tvb, offset, options_len, "Options: (%u bytes)", options_len);
974 dcp_options_tree = proto_item_add_subtree(dcp_item, ett_dcp_options);
976 dissect_options(tvb, pinfo, dcp_options_tree, tree, dcph, offset, offset + options_len);
979 offset+=options_len; /* Skip over Options */
981 /* Queuing tap data */
982 tap_queue_packet(dccp_tap, pinfo, dcph);
984 /* Call sub-dissectors */
986 if (!pinfo->in_error_pkt || tvb_length_remaining(tvb, offset) > 0)
987 decode_dccp_ports(tvb, offset, pinfo, tree, dcph->sport, dcph->dport);
991 void proto_register_dcp(void)
993 module_t *dcp_module;
995 static hf_register_info hf[] = {
997 { "Source Port", "dcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
1001 { "Destination Port", "dcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
1005 { "Source or Destination Port", "dcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
1008 { &hf_dcp_data_offset,
1009 { "Data Offset", "dcp.data_offset", FT_UINT8, BASE_DEC, NULL, 0x0,
1013 { "CCVal", "dcp.ccval", FT_UINT8, BASE_DEC, NULL, 0x0,
1017 { "Checksum Coverage", "dcp.cscov", FT_UINT8, BASE_DEC, NULL, 0x0,
1020 { &hf_dcp_checksum_bad,
1021 { "Bad Checksum", "dcp.checksum_bad", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1025 { "Checksum", "dcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1029 { "Reserved", "dcp.res1", FT_UINT8, BASE_HEX, NULL, 0x0,
1033 { "Reserved", "dcp.res2", FT_UINT8, BASE_HEX, NULL, 0x0,
1037 { "Type", "dcp.type", FT_UINT8, BASE_DEC, VALS(dcp_packet_type_vals), 0x0,
1041 { "Extended Sequence Numbers", "dcp.x", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1045 { "Sequence Number", "dcp.seq", FT_UINT64, BASE_DEC, NULL, 0x0,
1049 { "Reserved", "dcp.ack_res", FT_UINT16, BASE_HEX, NULL, 0x0,
1053 { "Acknowledgement Number", "dcp.ack", FT_UINT64, BASE_DEC, NULL, 0x0,
1056 { &hf_dcp_service_code,
1057 { "Service Code", "dcp.service_code", FT_UINT32, BASE_DEC, NULL, 0x0,
1060 { &hf_dcp_reset_code,
1061 { "Reset Code", "dcp.reset_code", FT_UINT8, BASE_DEC, VALS(dcp_reset_code_vals), 0x0,
1065 { "Data 1", "dcp.data1", FT_UINT8, BASE_DEC, NULL, 0x0,
1069 { "Data 2", "dcp.data2", FT_UINT8, BASE_DEC, NULL, 0x0,
1073 { "Data 3", "dcp.data3", FT_UINT8, BASE_DEC, NULL, 0x0,
1076 { &hf_dcp_option_type,
1077 { "Option Type", "dcp.option_type", FT_UINT8, BASE_DEC, NULL, 0x0,
1080 { &hf_dcp_feature_number,
1081 { "Feature Number", "dcp.feature_number", FT_UINT8, BASE_DEC, NULL, 0x0,
1084 { &hf_dcp_ndp_count,
1085 { "NDP Count", "dcp.ndp_count", FT_UINT32, BASE_DEC, NULL, 0x0,
1088 { &hf_dcp_timestamp,
1089 { "Timestamp", "dcp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
1092 { &hf_dcp_timestamp_echo,
1093 { "Timestamp Echo", "dcp.timestamp_echo", FT_UINT32, BASE_DEC, NULL, 0x0,
1096 { &hf_dcp_elapsed_time,
1097 { "Elapsed Time", "dcp.elapsed_time", FT_UINT32, BASE_DEC, NULL, 0x0,
1100 { &hf_dcp_data_checksum,
1101 { "Data Checksum", "dcp.checksum_data", FT_UINT32, BASE_HEX, NULL, 0x0,
1104 { &hf_dcp_malformed,
1105 { "Malformed", "dcp.malformed", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1109 { "Options", "dcp.options", FT_NONE, BASE_DEC, NULL, 0x0,
1110 "DCP Options fields", HFILL }}
1114 static gint *ett[] = {
1119 proto_dcp = proto_register_protocol("Datagram Congestion Control Protocol", "DCP", "dcp");
1120 proto_register_field_array(proto_dcp, hf, array_length(hf));
1121 proto_register_subtree_array(ett, array_length(ett));
1124 dcp_subdissector_table = register_dissector_table("dcp.port", "DCP port", FT_UINT16, BASE_DEC);
1125 register_heur_dissector_list("dcp", &heur_subdissector_list);
1127 /* reg preferences */
1128 dcp_module = prefs_register_protocol(proto_dcp, NULL);
1129 prefs_register_bool_preference(dcp_module, "summary_in_tree",
1130 "Show DCCP summary in protocol tree",
1131 "Whether the DCCP summary line should be shown in the protocol tree",
1132 &dcp_summary_in_tree);
1134 prefs_register_bool_preference(dcp_module, "try_heuristic_first",
1135 "Try heuristic sub-dissectors first",
1136 "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector "
1137 "registered to a specific port",
1138 &try_heuristic_first);
1140 prefs_register_bool_preference(dcp_module, "check_checksum",
1141 "Check the validity of the DCCP checksum when possible",
1142 "Whether to check the validity of the DCCP checksum",
1143 &dccp_check_checksum);
1146 void proto_reg_handoff_dcp(void)
1148 dissector_handle_t dcp_handle;
1150 dcp_handle = create_dissector_handle(dissect_dcp, proto_dcp);
1151 dissector_add("ip.proto", IP_PROTO_DCCP, dcp_handle);
1152 data_handle = find_dissector("data");
1153 dccp_tap = register_tap("dccp");