s/%ll/%" G_GINT64_MODIFIER "/g
[obnox/wireshark/wip.git] / epan / dissectors / packet-dcp.c
1 /* packet-dcp.c
2  * Routines for Datagram Congestion Control Protocol, "DCCP" dissection:
3  * it should be conformance to draft-ietf-dccp-spec-11.txt
4  *
5  * Copyright 2005 _FF_
6  *
7  * Francesco Fondelli <francesco dot fondelli, gmail dot com>
8  *
9  * $Id$
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * Copied from packet-udp.c
16  *
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.
21  *
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.
26  *
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.
30  */
31
32
33 /* NOTES:
34  *
35  * PROTOABBREV name collision problem, 'dccp' is used by
36  * Distributed Checksum Clearinghouse Protocol.
37  * This dissector should be named packet-dccp.c IMHO.
38  *
39  * Nov 13, 2006: makes checksum computation dependent
40  * upon the header CsCov field (cf. RFC 4340, 5.1)
41  * (Gerrit Renker)
42  *
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))
46  * (Gerrit Renker)
47  *
48  * Jan 29, 2007: updates the offsets of the timestamps to be
49  * compliant to (cf. RFC 4342, sec. 13).
50  * (Gerrit Renker)
51  */
52
53 #ifdef HAVE_CONFIG_H
54 # include "config.h"
55 #endif
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60
61 #include <glib.h>
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>
68
69 #include "packet-dcp.h"
70
71 #include "packet-ip.h"
72 #include <epan/conversation.h>
73 #include <epan/tap.h>
74
75 /* Some definitions and the dissect_options() logic have been taken from Arnaldo Carvalho de Melo's DCCP implementation, thanks! */
76
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)
82
83
84 static const value_string dcp_packet_type_vals[] = {
85         {0x0, "Request"},
86         {0x1, "Response"},
87         {0x2, "Data"},
88         {0x3, "Ack"},
89         {0x4, "DataAck"},
90         {0x5, "CloseReq"},
91         {0x6, "Close"},
92         {0x7, "Reset"},
93         {0x8, "Sync"},
94         {0x9, "SyncAck"},
95         {0xA, "Reserved"},
96         {0xB, "Reserved"},
97         {0xC, "Reserved"},
98         {0xD, "Reserved"},
99         {0xE, "Reserved"},
100         {0xF, "Reserved"},
101         {0, NULL}
102 };
103
104 static const value_string dcp_reset_code_vals[] = {
105         {0x00, "Unspecified"},
106         {0x01, "Closed"},
107         {0x02, "Aborted"},
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"},
114         {0x09, "Too Busy"},
115         {0x0A, "Bad Init Cookie"},
116         {0x0B, "Aggression Penalty"},
117         {0x0C, "Reserved"},
118         {0, NULL}
119 };
120
121 static const value_string dcp_feature_options_vals[] = {
122         {0x20, "Change L"},
123         {0x21, "Confirm L"},
124         {0x22, "Change R"},
125         {0x23, "Confirm R"},
126         {0, NULL}
127 };
128
129 static const value_string dcp_feature_numbers_vals[] = {
130         {0x01, "CCID"},
131         {0x02, "Allow Short Seqnos"},
132         {0x03, "Sequence Window"},
133         {0x04, "ECN Incapable"},
134         {0x05, "Ack Ratio"},
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 */
140         {0, NULL}
141 };
142
143
144 #if 0
145 #define DBG(str, args...)       do {\
146                                         fprintf(stdout, \
147                                         "[%s][%s][%d]: ",\
148                                         __FILE__, \
149                                         __FUNCTION__, \
150                                         __LINE__); \
151                                         fflush(stdout); \
152                                         fprintf(stdout, str, ## args); \
153                                 } while (0)
154 #else
155 #define DBG0(format)
156 #define DBG1(format, arg1)
157 #define DBG2(format, arg1, arg2)
158 #endif /* 0/1 */
159
160
161 static int proto_dcp = -1;
162 static int dccp_tap = -1;
163
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;
177
178 static int hf_dcp_ack_res = -1;
179 static int hf_dcp_ack = -1;
180
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;
186
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;
195
196 static int hf_dcp_malformed = -1;
197
198 static gint ett_dcp = -1;
199 static gint ett_dcp_options = -1;
200
201 static dissector_table_t dcp_subdissector_table;
202 static heur_dissector_list_t heur_subdissector_list;
203 static dissector_handle_t data_handle;
204
205 /* preferences */
206 static gboolean dcp_summary_in_tree = TRUE;
207 static gboolean try_heuristic_first = FALSE;
208 static gboolean dccp_check_checksum = TRUE;
209
210
211 static void
212 decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int sport, int dport)
213 {
214         tvbuff_t *next_tvb;
215         int low_port, high_port;
216
217         next_tvb = tvb_new_subset(tvb, offset, -1, -1);
218
219         /* determine if this packet is part of a conversation and call dissector */
220         /* for the conversation if available */
221
222         if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_DCCP, sport, dport, next_tvb, pinfo, tree)) {
223                 return;
224         }
225
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)) {
229                         return;
230                 }
231         }
232
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:
237
238            1) we pick the same dissector for traffic going in both directions;
239
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);
242
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. */
247
248         if (sport > dport) {
249                 low_port = dport;
250                 high_port = sport;
251         } else {
252                 low_port = sport;
253                 high_port = dport;
254         }
255         if (low_port != 0 &&
256             dissector_try_port(dcp_subdissector_table, low_port, next_tvb, pinfo, tree)) {
257                 return;
258         }
259         if (high_port != 0 &&
260             dissector_try_port(dcp_subdissector_table, high_port, next_tvb, pinfo, tree)) {
261                 return;
262         }
263
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)) {
267                         return;
268                 }
269         }
270
271         /* Oh, well, we don't know this; dissect it as data. */
272         call_dissector(data_handle, next_tvb, pinfo, tree);
273 }
274
275 /*
276  *      Auxiliary functions to dissect DCCP options
277  */
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)
280 {
281         const guint8* ptr;
282         guint64 value = 0;
283
284         ptr = tvb_get_ptr(tvb, offset, nbytes);
285         if (nbytes > 5)
286                 value += ((guint64)*ptr++) << 40;
287         if (nbytes > 4)
288                 value += ((guint64)*ptr++) << 32;
289         if (nbytes > 3)
290                 value += ((guint64)*ptr++) << 24;
291         if (nbytes > 2)
292                 value += ((guint64)*ptr++) << 16;
293         if (nbytes > 1)
294                 value += ((guint64)*ptr++) << 8;
295         if (nbytes > 0)
296                 value += *ptr;
297
298         return value;
299 }
300
301 static void dissect_feature_options(proto_tree *dcp_options_tree, tvbuff_t *tvb, int offset, guint8 option_len,
302                                     guint8 option_type)
303 {
304         guint8 feature_number = tvb_get_guint8(tvb, offset + 2);
305         proto_item *dcp_item;
306         int i;
307
308         proto_tree_add_uint_hidden(dcp_options_tree, hf_dcp_feature_number, tvb, offset + 2, 1, feature_number);
309
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"));
312
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));
328                 break;
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"));
334
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));
337                 break;
338         /* Reserved, specific, or unknown features */
339         default:
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);
345                 else
346                         proto_item_append_text(dcp_item, "Unknown feature number %d", feature_number);
347                 break;
348         }
349         proto_item_append_text(dcp_item, ")");
350 }
351
352 /*
353  * This function dissects DCCP options
354  */
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_,
356                             int offset_start,
357                             int offset_end)
358 {
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;
363         int i;
364         guint32 p;
365         proto_item *dcp_item = NULL;
366
367         while( offset < offset_end ) {
368
369                 /* DBG("offset==%d\n", offset); */
370
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);
374
375                 if (option_type >= 32) {                               /* variable length options */
376
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);
381                         }
382
383                         option_len = tvb_get_guint8(tvb, offset + 1);
384
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);
389                         }
390
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);
395                         }
396
397                 } else {                                               /* 1byte options */
398                         option_len = 1;
399                 }
400
401                 switch (option_type) {
402
403                 case 0:
404                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Padding");
405                         break;
406
407                 case 1:
408                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Mandatory");
409                         break;
410
411                 case 2:
412                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Slow Receiver");
413                         break;
414
415                 case 32:
416                 case 33:
417                 case 34:
418                 case 35:
419                         dissect_feature_options(dcp_options_tree, tvb, offset, option_len, option_type);
420                         break;
421
422                 case 36:
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++) {
425                                 if(i==0)
426                                         proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
427                                 else
428                                         proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
429                         }
430                         proto_item_append_text(dcp_item, ")");
431                         break;
432
433                 case 37:
434                         if (option_len > 8)
435                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count too long (max 6 bytes)");
436                         else
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));
439                         break;
440
441                 case 38:
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));
445                         break;
446
447                 case 39:
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, ")");
452                         break;
453
454                 case 40:
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));
458                         break;
459
460                 case 41:
461                         if(option_len==6)
462                                 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp, tvb, offset + 2, 4,
463                                                     tvb_get_ntohl(tvb, offset + 2));
464                         else
465                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
466                                                     "Timestamp too long [%u != 6]", option_len);
467                         break;
468
469                 case 42:
470                         if(option_len==6)
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));
476
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));
482
483                                 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 6, 4,
484                                                     tvb_get_ntohl(tvb, offset + 6));
485                         } else
486                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Timestamp Echo length");
487                         break;
488
489                 case 43:
490                         if(option_len==4)
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));
496                         else
497                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Elapsed Time length");
498                         break;
499
500                 case 44:
501                         if(option_len==6) {
502                                 proto_tree_add_uint(dcp_options_tree, hf_dcp_data_checksum, tvb, offset + 2, 4,
503                                                     tvb_get_ntohl(tvb, offset + 2));
504                         } else
505                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Data checksum length");
506                         break;
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 */
511                                 if (p == 0xFFFFFFFF)
512                                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: 0 (or max)");
513                                 else
514                                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID3 Loss Event Rate: %u", p);
515                         } else
516                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong CCID3 Loss Event Rate length");
517                         break;
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 */
521                         break;
522                 case 194:       /* RFC 4342, 8.3 */
523                         if(option_len == 6)
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));
526                         else
527                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong CCID3 Receive Rate length");
528                         break;
529                 default :
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");
533                                 break;
534                         }
535
536                         if (option_type >= 128) {
537                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID option %d", option_type);
538                                 break;
539                         }
540
541                         /* if here we don't know this option */
542                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Unknown");
543                         break;
544
545                 } /* end switch() */
546
547                 offset+=option_len; /* Skip over the dissected option */
548
549         } /* end while() */
550 }
551 /* compute DCCP checksum coverage according to RFC 4340, section 9 */
552 static inline guint dccp_csum_coverage(const e_dcphdr *dcph, guint len)
553 {
554         guint cov;
555
556         if (dcph->cscov == 0)
557                 return len;
558         cov = (dcph->data_offset + dcph->cscov - 1) * sizeof(guint32);
559         return (cov > len)? len : cov;
560 }
561
562 static void dissect_dcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
563 {
564         proto_tree *dcp_tree = NULL;
565         proto_tree *dcp_options_tree = NULL;
566         proto_item *dcp_item = NULL;
567
568         vec_t      cksum_vec[4];
569         guint32    phdr[2];
570         guint16    computed_cksum;
571         guint      offset = 0;
572         guint      len = 0;
573         guint      reported_len = 0;
574         guint      advertised_dccp_header_len = 0;
575         guint      options_len = 0;
576         e_dcphdr   *dcph;
577
578         /* get at least a full message header */
579         if(tvb_length(tvb) < DCCP_HDR_LEN_MIN) {
580                 /* DBG("malformed\n"); */
581                 if (tree)
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);
586         }
587
588         dcph=ep_alloc(sizeof(e_dcphdr));
589
590         memset(dcph, 0, sizeof(e_dcphdr));
591
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);
594
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);
599
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); */
605
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;
610
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;
616         dcph->ccval >>= 4;
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;
621         dcph->reserved1>>=5;
622         /* DBG("dcph->reserved1: %d\n", dcph->reserved1); */
623         dcph->type=tvb_get_guint8(tvb, offset+8)&0x1E;
624         dcph->type>>=1;
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); */
628         if(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);
633                 }
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);
637                 dcph->seq<<=32;
638                 dcph->seq+=tvb_get_ntohl(tvb, offset+12);
639                 /* DBG("dcph->seq[48bits]: %" G_GINT64_MODIFIER "u\n", dcph->seq); */
640         } else {
641                 dcph->seq=tvb_get_guint8(tvb, offset+9);
642                 dcph->seq<<=16;
643                 dcph->seq+=tvb_get_ntohs(tvb, offset+10);
644                 /* DBG("dcph->seq[24bits]: %" G_GINT64_MODIFIER "u\n", dcph->seq); */
645         }
646
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"),
652                              dcph->seq);
653
654
655         if (tree) {
656                 if(dcp_summary_in_tree) {
657                         dcp_item =
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"),
664                                                                dcph->seq);
665                 } else {
666                         dcp_item = proto_tree_add_item(tree, proto_dcp, tvb, offset, 8, FALSE);
667                 }
668
669                 dcp_tree = proto_item_add_subtree(dcp_item, ett_dcp);
670
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);
675
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);
678
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);
682
683                 /* checksum analysis taken from packet-udp (difference: mandatory checksums in DCCP) */
684
685                 reported_len = tvb_reported_length(tvb);
686                 len = tvb_length(tvb);
687                 if (!pinfo->fragmented && len >= reported_len) {
688
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
692                            reassembly? */
693
694                         if (dccp_check_checksum) {
695
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) {
703
704                                 case AT_IPv4:
705                                         phdr[0] = g_htonl((IP_PROTO_DCCP<<16) + reported_len);
706                                         cksum_vec[2].len = 4;
707                                         break;
708                                 case AT_IPv6:
709                                         phdr[0] = g_htonl(reported_len);
710                                         phdr[1] = g_htonl(IP_PROTO_DCCP);
711                                         cksum_vec[2].len = 8;
712                                         break;
713
714                                 default:
715                                         /* DCCP runs only atop IPv4 and IPv6.... */
716                                   /*DISSECTOR_ASSERT_NOT_REACHED();*/
717                                         break;
718                                 }
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);
726                                 } else {
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));
731                                 }
732                         } else {
733                                 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
734                                                                  offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
735                         }
736                 } else {
737                         proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
738                                                          offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
739                 }
740
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);
744                 if(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);
747                 } else {
748                         proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 9, 3, dcph->seq);
749
750                 }
751         }
752
753         if(dcph->x)
754                 offset+=16; /* Skip over extended Generic header */
755         else
756                 offset+=12; /* Skip over not extended Generic header */
757
758         /* dissecting type depending additional fields */
759         switch(dcph->type) {
760
761         case 0x0: /* DCCP-Request */
762                 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
763                         if(tree)
764                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
765                         return;
766                 }
767                 dcph->service_code=tvb_get_ntohl(tvb, offset);
768                 if(tree)
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);
772
773                 offset+=4; /* Skip over service code */
774                 break;
775
776         case 0x1: /* DCCP-Response */
777                 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
778                         if(tree)
779                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
780                         return;
781                 }
782                 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
783                 if(tree)
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);
786                 dcph->ack<<=32;
787                 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
788
789                 if(tree)
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);
793
794                 offset+=8; /* Skip over Acknowledgement Number Subheader */
795
796                 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
797                         if(tree)
798                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
799                         return;
800                 }
801                 dcph->service_code=tvb_get_ntohl(tvb, offset);
802                 if(tree)
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);
806
807                 offset+=4; /* Skip over service code */
808                 break;
809
810         case 0x2: /* DCCP-Data */
811                 /* nothing to dissect */
812                 break;
813
814         case 0x3: /* DCCP-Ack */
815         case 0x4: /* DCCP-DataAck */
816                 if(dcph->x) {
817                         if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
818                                 if(tree)
819                                         proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
820                                 return;
821                         }
822                         dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
823                         if(tree)
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);
826                         dcph->ack<<=32;
827                         dcph->ack+=tvb_get_ntohl(tvb, offset+4);
828                         if(tree)
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);
832
833                         offset+=8; /* Skip over Acknowledgement Number Subheader */
834                 } else {
835                         if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
836                                 if(tree)
837                                         proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
838                                 return;
839                         }
840                         dcph->ack_reserved=tvb_get_guint8(tvb, offset);
841                         if(tree)
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);
844                         dcph->ack<<=16;
845                         dcph->ack+=tvb_get_ntohs(tvb, offset+2);
846                         if(tree)
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);
850
851                         offset+=4; /* Skip over Acknowledgement Number Subheader */
852                 }
853                 break;
854
855         case 0x7: /* DCCP-Reset */
856                 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
857                         if(tree)
858                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
859                         return;
860                 }
861                 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
862                 if(tree)
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);
865                 dcph->ack<<=32;
866                 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
867                 if(tree)
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);
871
872                 offset+=8; /* Skip over Acknowledgement Number Subheader */
873
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);
878                 if(tree) {
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);
883                 }
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"));
886
887                 offset+=4; /* Skip over Reset Code and data123 */
888                 break;
889
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 */
895                         if(tree)
896                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
897                         return;
898                 }
899                 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
900                 if(tree)
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);
903                 dcph->ack<<=32;
904                 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
905                 if(tree)
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);
909
910                 offset+=8; /* Skip over Acknowledgement Number Subheader */
911                 break;
912
913         default:
914                 if(tree)
915                         proto_tree_add_text(dcp_tree, tvb, offset, -1, "Reserved packet type: unable to dissect further");
916                 return;
917                 break;
918         }
919
920
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.
923          */
924
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;
928
929         if ( advertised_dccp_header_len > DCCP_HDR_LEN_MAX ) {
930                 if(tree)
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);
934                 return;
935         }
936
937         if(tvb_length(tvb) < advertised_dccp_header_len) {
938                 if(tree)
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));
941                 return;
942         }
943
944         if(options_len > DCCP_OPT_LEN_MAX) {
945                 /* DBG("malformed\n"); */
946                 if(tree)
947                         proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
948                 THROW(ReportedBoundsError);
949         }
950
951
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) {
956                 if(tree) {
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);
961                 }
962                 THROW(ReportedBoundsError);
963         } else {
964                 if(dcp_tree) {
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);
967                 }
968                 dissect_options(tvb, pinfo, dcp_options_tree, tree, dcph, offset, offset + options_len);
969         }
970
971         offset+=options_len; /* Skip over Options */
972
973         /* Queuing tap data */
974         tap_queue_packet(dccp_tap, pinfo, dcph);
975
976         /* Call sub-dissectors */
977
978         if (!pinfo->in_error_pkt || tvb_length_remaining(tvb, offset) > 0)
979                 decode_dccp_ports(tvb, offset, pinfo, tree, dcph->sport, dcph->dport);
980 }
981
982
983 void proto_register_dcp(void)
984 {
985         module_t *dcp_module;
986
987         static hf_register_info hf[] = {
988                 { &hf_dcp_srcport,
989                 { "Source Port",        "dcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
990                   "", HFILL }},
991
992                 { &hf_dcp_dstport,
993                 { "Destination Port",   "dcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
994                   "", HFILL }},
995
996                 { &hf_dcp_port,
997                 { "Source or Destination Port", "dcp.port", FT_UINT16, BASE_DEC,  NULL, 0x0,
998                   "", HFILL }},
999
1000                 { &hf_dcp_data_offset,
1001                 { "Data Offset",        "dcp.data_offset", FT_UINT8, BASE_DEC, NULL, 0x0,
1002                   "", HFILL }},
1003
1004                 { &hf_dcp_ccval,
1005                 { "CCVal",              "dcp.ccval", FT_UINT8, BASE_DEC,  NULL, 0x0,
1006                   "", HFILL }},
1007
1008                 { &hf_dcp_cscov,
1009                 { "Checksum Coverage",  "dcp.cscov", FT_UINT8, BASE_DEC,  NULL, 0x0,
1010                   "", HFILL }},
1011
1012                 { &hf_dcp_checksum_bad,
1013                 { "Bad Checksum",       "dcp.checksum_bad", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1014                   "", HFILL }},
1015
1016                 { &hf_dcp_checksum,
1017                 { "Checksum",           "dcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1018                   "", HFILL }},
1019
1020                 { &hf_dcp_res1,
1021                 { "Reserved",           "dcp.res1", FT_UINT8, BASE_HEX, NULL, 0x0,
1022                   "", HFILL }},
1023
1024                 { &hf_dcp_res2,
1025                 { "Reserved",           "dcp.res2", FT_UINT8, BASE_HEX, NULL, 0x0,
1026                   "", HFILL }},
1027
1028                 { &hf_dcp_type,
1029                 { "Type",               "dcp.type", FT_UINT8, BASE_DEC, VALS(dcp_packet_type_vals), 0x0,
1030                   "", HFILL }},
1031
1032                 { &hf_dcp_x,
1033                 { "Extended Sequence Numbers", "dcp.x", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1034                   "", HFILL }},
1035
1036                 { &hf_dcp_seq,
1037                 { "Sequence Number",    "dcp.seq", FT_UINT64, BASE_DEC, NULL, 0x0,
1038                   "", HFILL }},
1039
1040                 { &hf_dcp_ack_res,
1041                 { "Reserved",           "dcp.ack_res", FT_UINT16, BASE_HEX, NULL, 0x0,
1042                   "", HFILL }},
1043
1044                 { &hf_dcp_ack,
1045                 { "Acknowledgement Number", "dcp.ack", FT_UINT64, BASE_DEC, NULL, 0x0,
1046                   "", HFILL }},
1047
1048                 { &hf_dcp_service_code,
1049                 { "Service Code", "dcp.service_code", FT_UINT32, BASE_DEC, NULL, 0x0,
1050                   "", HFILL }},
1051
1052                 { &hf_dcp_reset_code,
1053                 { "Reset Code", "dcp.reset_code", FT_UINT8, BASE_DEC, VALS(dcp_reset_code_vals), 0x0,
1054                   "", HFILL }},
1055
1056                 { &hf_dcp_data1,
1057                 { "Data 1",     "dcp.data1", FT_UINT8, BASE_DEC, NULL, 0x0,
1058                   "", HFILL }},
1059
1060                 { &hf_dcp_data2,
1061                 { "Data 2",     "dcp.data2", FT_UINT8, BASE_DEC, NULL, 0x0,
1062                   "", HFILL }},
1063
1064                 { &hf_dcp_data3,
1065                 { "Data 3",     "dcp.data3", FT_UINT8, BASE_DEC, NULL, 0x0,
1066                   "", HFILL }},
1067
1068                 { &hf_dcp_option_type,
1069                 { "Option Type",     "dcp.option_type", FT_UINT8, BASE_DEC, NULL, 0x0,
1070                   "", HFILL }},
1071
1072                 { &hf_dcp_feature_number,
1073                 { "Feature Number",   "dcp.feature_number", FT_UINT8, BASE_DEC, NULL, 0x0,
1074                   "", HFILL }},
1075
1076                 { &hf_dcp_ndp_count,
1077                 { "NDP Count",   "dcp.ndp_count", FT_UINT64, BASE_DEC, NULL, 0x0,
1078                   "", HFILL }},
1079
1080                 { &hf_dcp_timestamp,
1081                 { "Timestamp",   "dcp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
1082                   "", HFILL }},
1083
1084                 { &hf_dcp_timestamp_echo,
1085                 { "Timestamp Echo",   "dcp.timestamp_echo", FT_UINT32, BASE_DEC, NULL, 0x0,
1086                   "", HFILL }},
1087
1088                 { &hf_dcp_elapsed_time,
1089                 { "Elapsed Time",   "dcp.elapsed_time", FT_UINT32, BASE_DEC, NULL, 0x0,
1090                   "", HFILL }},
1091
1092                 { &hf_dcp_data_checksum,
1093                 { "Data Checksum",  "dcp.checksum_data", FT_UINT32, BASE_HEX, NULL, 0x0,
1094                   "", HFILL }},
1095
1096                 { &hf_dcp_malformed,
1097                 { "Malformed", "dcp.malformed", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1098                   "", HFILL }},
1099
1100                 { &hf_dcp_options,
1101                 { "Options", "dcp.options", FT_NONE, BASE_DEC, NULL, 0x0,
1102                   "DCP Options fields", HFILL }}
1103
1104         };
1105
1106         static gint *ett[] = {
1107                 &ett_dcp,
1108                 &ett_dcp_options
1109         };
1110
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));
1114
1115         /* subdissectors */
1116         dcp_subdissector_table = register_dissector_table("dcp.port", "DCP port", FT_UINT16, BASE_DEC);
1117         register_heur_dissector_list("dcp", &heur_subdissector_list);
1118
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);
1125
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);
1131
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);
1136 }
1137
1138 void proto_reg_handoff_dcp(void)
1139 {
1140         dissector_handle_t dcp_handle;
1141
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");
1146 }