Use G_GINT64_MODIFIER, rather than the PRI[douxX]64 macros, for GLib
[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_numbers_vals[] = {
122         {0x01, "CCID"},
123         {0x02, "Allow Short Seqnos"},
124         {0x03, "Sequence Window"},
125         {0x04, "ECN Incapable"},
126         {0x05, "Ack Ratio"},
127         {0x06, "Send Ack Vector"},
128         {0x07, "Send NDP Count"},
129         {0x08, "Minimum Checksum Coverage"},
130         {0x09, "Check Data Checksum"},
131         {0, NULL}
132 };
133
134
135 #if 0
136 #define DBG(str, args...)       do {\
137                                         fprintf(stdout, \
138                                         "[%s][%s][%d]: ",\
139                                         __FILE__, \
140                                         __FUNCTION__, \
141                                         __LINE__); \
142                                         fflush(stdout); \
143                                         fprintf(stdout, str, ## args); \
144                                 } while (0)
145 #else
146 #define DBG0(format)
147 #define DBG1(format, arg1)
148 #define DBG2(format, arg1, arg2)
149 #endif /* 0/1 */
150
151
152 static int proto_dcp = -1;
153 static int dccp_tap = -1;
154
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;
168
169 static int hf_dcp_ack_res = -1;
170 static int hf_dcp_ack = -1;
171
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;
177
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;
186
187 static int hf_dcp_malformed = -1;
188
189 static gint ett_dcp = -1;
190 static gint ett_dcp_options = -1;
191
192 static dissector_table_t dcp_subdissector_table;
193 static heur_dissector_list_t heur_subdissector_list;
194 static dissector_handle_t data_handle;
195
196 /* preferences */
197 static gboolean dcp_summary_in_tree = TRUE;
198 static gboolean try_heuristic_first = FALSE;
199 static gboolean dccp_check_checksum = TRUE;
200
201
202 static void
203 decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int sport, int dport)
204 {
205         tvbuff_t *next_tvb;
206         int low_port, high_port;
207
208         next_tvb = tvb_new_subset(tvb, offset, -1, -1);
209
210         /* determine if this packet is part of a conversation and call dissector */
211         /* for the conversation if available */
212
213         if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_DCCP, sport, dport, next_tvb, pinfo, tree)) {
214                 return;
215         }
216
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)) {
220                         return;
221                 }
222         }
223
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:
228
229            1) we pick the same dissector for traffic going in both directions;
230
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);
233
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. */
238
239         if (sport > dport) {
240                 low_port = dport;
241                 high_port = sport;
242         } else {
243                 low_port = sport;
244                 high_port = dport;
245         }
246         if (low_port != 0 &&
247             dissector_try_port(dcp_subdissector_table, low_port, next_tvb, pinfo, tree)) {
248                 return;
249         }
250         if (high_port != 0 &&
251             dissector_try_port(dcp_subdissector_table, high_port, next_tvb, pinfo, tree)) {
252                 return;
253         }
254
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)) {
258                         return;
259                 }
260         }
261
262         /* Oh, well, we don't know this; dissect it as data. */
263         call_dissector(data_handle, next_tvb, pinfo, tree);
264 }
265
266
267 /*
268  * This function dissects DCCP options
269  */
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_,
271                             int offset_start,
272                             int offset_end)
273 {
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;
279         int i;
280         proto_item *dcp_item = NULL;
281
282         while( offset < offset_end ) {
283
284                 /* DBG("offset==%d\n", offset); */
285
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);
289
290                 if (option_type >= 32) {                               /* variable length options */
291
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);
296                         }
297
298                         option_len = tvb_get_guint8(tvb, offset + 1);
299
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);
304                         }
305
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);
310                         }
311
312                 } else {                                               /* 1byte options */
313                         option_len = 1;
314                 }
315
316                 switch (option_type) {
317
318                 case 0:
319                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Padding");
320                         break;
321
322                 case 1:
323                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Mandatory");
324                         break;
325
326                 case 2:
327                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Slow Receiver");
328                         break;
329
330                 case 32:
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);
333
334                         if( (feature_number < 10) && (feature_number!=0) ) {
335                                 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
336                                                                "Change L(%s",
337                                                                val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
338                                 for (i = 0; i < option_len - 3; i++) {
339                                         if(i==0)
340                                                 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
341                                         else
342                                                 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
343                                 }
344                                 proto_item_append_text(dcp_item, ")");
345                         } else {
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)");
349                                 else
350                                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
351                                                             "Change L(CCID-specific features)");
352                         }
353                         break;
354
355                 case 33:
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);
358
359                         if( (feature_number < 10) && (feature_number!=0) ) {
360                                 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
361                                                                "Confirm L(%s",
362                                                                val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
363                                 for (i = 0; i < option_len - 3; i++) {
364                                         if(i==0)
365                                                 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
366                                         else
367                                                 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
368                                 }
369                                 proto_item_append_text(dcp_item, ")");
370                         } else {
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)");
374                                 else
375                                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
376                                                             "Confirm L(CCID-specific features)");
377                         }
378                         break;
379
380                 case 34:
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);
383
384                         if( (feature_number < 10) && (feature_number!=0) ) {
385                                 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
386                                                                "Change R(%s",
387                                                                val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
388                                 for (i = 0; i < option_len - 3; i++) {
389                                         if(i==0)
390                                                 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
391                                         else
392                                                 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
393                                 }
394                                 proto_item_append_text(dcp_item, ")");
395                         } else {
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)");
399                                 else
400                                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
401                                                             "Change R(CCID-specific features)");
402                         }
403                         break;
404
405                 case 35:
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);
408
409                         if( (feature_number < 10) && (feature_number!=0) ) {
410                                 dcp_item = proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
411                                                                "Confirm R(%s",
412                                                                val_to_str(feature_number, dcp_feature_numbers_vals, "Unknown Type"));
413                                 for (i = 0; i < option_len - 3; i++) {
414                                         if(i==0)
415                                                 proto_item_append_text(dcp_item, "%d", tvb_get_guint8(tvb, offset + 3 + i));
416                                         else
417                                                 proto_item_append_text(dcp_item, ", %d", tvb_get_guint8(tvb, offset + 3 + i));
418                                 }
419                                 proto_item_append_text(dcp_item, ")");
420                         } else {
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)");
424                                 else
425                                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
426                                                             "Confirm R(CCID-specific features)");
427                         }
428                         break;
429
430                 case 36:
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++) {
433                                 if(i==0)
434                                         proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
435                                 else
436                                         proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
437                         }
438                         proto_item_append_text(dcp_item, ")");
439                         break;
440
441                 case 37:
442                         if(option_len==3)
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));
451                         else
452                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "NDP Count too long (max 3 bytes)");
453
454                         break;
455
456                 case 38:
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++) {
459                                 if(i==0)
460                                         proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
461                                 else
462                                         proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
463                         }
464                         proto_item_append_text(dcp_item, ")");
465                         break;
466
467                 case 39:
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++) {
470                                 if(i==0)
471                                         proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
472                                 else
473                                         proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
474                         }
475                         proto_item_append_text(dcp_item, ")");
476                         break;
477
478                 case 40:
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++) {
481                                 if(i==0)
482                                         proto_item_append_text(dcp_item, "%02x", tvb_get_guint8(tvb, offset + 2 + i));
483                                 else
484                                         proto_item_append_text(dcp_item, " %02x", tvb_get_guint8(tvb, offset + 2 + i));
485                         }
486                         proto_item_append_text(dcp_item, ")");
487                         break;
488
489                 case 41:
490                         if(option_len==6)
491                                 proto_tree_add_uint(dcp_options_tree, hf_dcp_timestamp, tvb, offset + 2, 4,
492                                                     tvb_get_ntohl(tvb, offset + 2));
493                         else
494                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len,
495                                                     "Timestamp too long [%u != 6]", option_len);
496                         break;
497
498                 case 42:
499                         if(option_len==6)
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));
505
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));
511
512                                 proto_tree_add_uint(dcp_options_tree, hf_dcp_elapsed_time, tvb, offset + 6, 4,
513                                                     tvb_get_ntohl(tvb, offset + 6));
514                         } else
515                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Timestamp Echo length");
516                         break;
517
518                 case 43:
519                         if(option_len==4)
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));
525                         else
526                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Elapsed Time length");
527                         break;
528
529                 case 44:
530                         if(option_len==6) {
531                                 proto_tree_add_uint(dcp_options_tree, hf_dcp_data_checksum, tvb, offset + 2, 4,
532                                                     tvb_get_ntohl(tvb, offset + 2));
533                         } else
534                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Wrong Data checksum length");
535                         break;
536
537                 default :
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");
541                                 break;
542                         }
543
544                         if (option_type >= 128) {
545                                 proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "CCID option %d", option_type);
546                                 break;
547                         }
548
549                         /* if here we don't know this option */
550                         proto_tree_add_text(dcp_options_tree, tvb, offset, option_len, "Unknown");
551                         break;
552
553                 } /* end switch() */
554
555                 offset+=option_len; /* Skip over the dissected option */
556
557         } /* end while() */
558 }
559 /* compute DCCP checksum coverage according to RFC 4340, section 9 */
560 static inline guint dccp_csum_coverage(const e_dcphdr *dcph, guint len)
561 {
562         guint cov;
563
564         if (dcph->cscov == 0)
565                 return len;
566         cov = (dcph->data_offset + dcph->cscov - 1) * sizeof(guint32);
567         return (cov > len)? len : cov;
568 }
569
570 static void dissect_dcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
571 {
572         proto_tree *dcp_tree = NULL;
573         proto_tree *dcp_options_tree = NULL;
574         proto_item *dcp_item = NULL;
575
576         vec_t      cksum_vec[4];
577         guint32    phdr[2];
578         guint16    computed_cksum;
579         guint      offset = 0;
580         guint      len = 0;
581         guint      reported_len = 0;
582         guint      advertised_dccp_header_len = 0;
583         guint      options_len = 0;
584         e_dcphdr   *dcph;
585
586         /* get at least a full message header */
587         if(!tvb_bytes_exist(tvb, 0, DCCP_HDR_LEN_MIN)) {
588                 /* DBG("malformed\n"); */
589                 if (tree)
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);
594         }
595
596         dcph=ep_alloc(sizeof(e_dcphdr));
597
598         memset(dcph, 0, sizeof(e_dcphdr));
599
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);
602
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);
607
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); */
613
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;
618
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;
624         dcph->ccval >>= 4;
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;
629         dcph->reserved1>>=5;
630         /* DBG("dcph->reserved1: %d\n", dcph->reserved1); */
631         dcph->type=tvb_get_guint8(tvb, offset+8)&0x1E;
632         dcph->type>>=1;
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); */
636         if(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);
641                 }
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);
645                 dcph->seq<<=32;
646                 dcph->seq+=tvb_get_ntohl(tvb, offset+12);
647                 /* DBG("dcph->seq[48bits]: %llu\n", dcph->seq); */
648         } else {
649                 dcph->seq=tvb_get_guint8(tvb, offset+9);
650                 dcph->seq<<=16;
651                 dcph->seq+=tvb_get_ntohs(tvb, offset+10);
652                 /* DBG("dcph->seq[24bits]: %llu\n", dcph->seq); */
653         }
654
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"),
660                              dcph->seq);
661
662
663         if (tree) {
664                 if(dcp_summary_in_tree) {
665                         dcp_item =
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"),
672                                                                dcph->seq);
673                 } else {
674                         dcp_item = proto_tree_add_item(tree, proto_dcp, tvb, offset, 8, FALSE);
675                 }
676
677                 dcp_tree = proto_item_add_subtree(dcp_item, ett_dcp);
678
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);
683
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);
686
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);
690
691                 /* checksum analysis taken from packet-udp (difference: mandatory checksums in DCCP) */
692
693                 reported_len = tvb_reported_length(tvb);
694                 len = tvb_length(tvb);
695                 if (!pinfo->fragmented && len >= reported_len) {
696
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
700                            reassembly? */
701
702                         if (dccp_check_checksum) {
703
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) {
711
712                                 case AT_IPv4:
713                                         phdr[0] = g_htonl((IP_PROTO_DCCP<<16) + reported_len);
714                                         cksum_vec[2].len = 4;
715                                         break;
716                                 case AT_IPv6:
717                                         phdr[0] = g_htonl(reported_len);
718                                         phdr[1] = g_htonl(IP_PROTO_DCCP);
719                                         cksum_vec[2].len = 8;
720                                         break;
721
722                                 default:
723                                         /* DCCP runs only atop IPv4 and IPv6.... */
724                                   /*DISSECTOR_ASSERT_NOT_REACHED();*/
725                                         break;
726                                 }
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);
734                                 } else {
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));
739                                 }
740                         } else {
741                                 proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
742                                                                  offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
743                         }
744                 } else {
745                         proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
746                                                          offset + 6, 2, dcph->checksum, "0x%04x", dcph->checksum);
747                 }
748
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);
752                 if(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);
755                 } else {
756                         proto_tree_add_uint64(dcp_tree, hf_dcp_seq, tvb, offset + 9, 3, dcph->seq);
757
758                 }
759         }
760
761         if(dcph->x)
762                 offset+=16; /* Skip over extended Generic header */
763         else
764                 offset+=12; /* Skip over not extended Generic header */
765
766         /* dissecting type depending additional fields */
767         switch(dcph->type) {
768
769         case 0x0: /* DCCP-Request */
770                 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
771                         if(tree)
772                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
773                         return;
774                 }
775                 dcph->service_code=tvb_get_ntohl(tvb, offset);
776                 if(tree)
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);
780
781                 offset+=4; /* Skip over service code */
782                 break;
783
784         case 0x1: /* DCCP-Response */
785                 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
786                         if(tree)
787                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
788                         return;
789                 }
790                 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
791                 if(tree)
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);
794                 dcph->ack<<=32;
795                 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
796
797                 if(tree)
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);
801
802                 offset+=8; /* Skip over Acknowledgement Number Subheader */
803
804                 if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
805                         if(tree)
806                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
807                         return;
808                 }
809                 dcph->service_code=tvb_get_ntohl(tvb, offset);
810                 if(tree)
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);
814
815                 offset+=4; /* Skip over service code */
816                 break;
817
818         case 0x2: /* DCCP-Data */
819                 /* nothing to dissect */
820                 break;
821
822         case 0x3: /* DCCP-Ack */
823         case 0x4: /* DCCP-DataAck */
824                 if(dcph->x) {
825                         if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
826                                 if(tree)
827                                         proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
828                                 return;
829                         }
830                         dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
831                         if(tree)
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);
834                         dcph->ack<<=32;
835                         dcph->ack+=tvb_get_ntohl(tvb, offset+4);
836                         if(tree)
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);
840
841                         offset+=8; /* Skip over Acknowledgement Number Subheader */
842                 } else {
843                         if(!tvb_bytes_exist(tvb, offset, 4)) { /* at least 4 byte */
844                                 if(tree)
845                                         proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
846                                 return;
847                         }
848                         dcph->ack_reserved=tvb_get_guint8(tvb, offset);
849                         if(tree)
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);
852                         dcph->ack<<=16;
853                         dcph->ack+=tvb_get_ntohs(tvb, offset+2);
854                         if(tree)
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);
858
859                         offset+=4; /* Skip over Acknowledgement Number Subheader */
860                 }
861                 break;
862
863         case 0x7: /* DCCP-Reset */
864                 if(!tvb_bytes_exist(tvb, offset, 8)) { /* at least 8 byte */
865                         if(tree)
866                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
867                         return;
868                 }
869                 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
870                 if(tree)
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);
873                 dcph->ack<<=32;
874                 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
875                 if(tree)
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);
879
880                 offset+=8; /* Skip over Acknowledgement Number Subheader */
881
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);
886                 if(tree) {
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);
891                 }
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"));
894
895                 offset+=4; /* Skip over Reset Code and data123 */
896                 break;
897
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 */
903                         if(tree)
904                                 proto_tree_add_text(dcp_tree, tvb, offset, -1, "too short packet");
905                         return;
906                 }
907                 dcph->ack_reserved=tvb_get_ntohs(tvb, offset);
908                 if(tree)
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);
911                 dcph->ack<<=32;
912                 dcph->ack+=tvb_get_ntohl(tvb, offset+4);
913                 if(tree)
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);
917
918                 offset+=8; /* Skip over Acknowledgement Number Subheader */
919                 break;
920
921         default:
922                 if(tree)
923                         proto_tree_add_text(dcp_tree, tvb, offset, -1, "Reserved packet type: unable to dissect further");
924                 return;
925                 break;
926         }
927
928
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.
931          */
932
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;
936
937         if ( advertised_dccp_header_len > DCCP_HDR_LEN_MAX ) {
938                 if(tree)
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);
942                 return;
943         }
944
945         if(!tvb_bytes_exist(tvb, 0, advertised_dccp_header_len)) {
946                 if(tree)
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));
949                 return;
950         }
951
952         if(options_len > DCCP_OPT_LEN_MAX) {
953                 /* DBG("malformed\n"); */
954                 if(tree)
955                         proto_tree_add_boolean_hidden(dcp_tree, hf_dcp_malformed, tvb, offset, 0, TRUE);
956                 THROW(ReportedBoundsError);
957         }
958
959
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) {
964                 if(tree) {
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);
969                 }
970                 THROW(ReportedBoundsError);
971         } else {
972                 if(dcp_tree) {
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);
975                 }
976                 dissect_options(tvb, pinfo, dcp_options_tree, tree, dcph, offset, offset + options_len);
977         }
978
979         offset+=options_len; /* Skip over Options */
980
981         /* Queuing tap data */
982         tap_queue_packet(dccp_tap, pinfo, dcph);
983
984         /* Call sub-dissectors */
985
986         if (!pinfo->in_error_pkt || tvb_length_remaining(tvb, offset) > 0)
987                 decode_dccp_ports(tvb, offset, pinfo, tree, dcph->sport, dcph->dport);
988 }
989
990
991 void proto_register_dcp(void)
992 {
993         module_t *dcp_module;
994
995         static hf_register_info hf[] = {
996                 { &hf_dcp_srcport,
997                 { "Source Port",        "dcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
998                   "", HFILL }},
999
1000                 { &hf_dcp_dstport,
1001                 { "Destination Port",   "dcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
1002                   "", HFILL }},
1003
1004                 { &hf_dcp_port,
1005                 { "Source or Destination Port", "dcp.port", FT_UINT16, BASE_DEC,  NULL, 0x0,
1006                   "", HFILL }},
1007
1008                 { &hf_dcp_data_offset,
1009                 { "Data Offset",        "dcp.data_offset", FT_UINT8, BASE_DEC, NULL, 0x0,
1010                   "", HFILL }},
1011
1012                 { &hf_dcp_ccval,
1013                 { "CCVal",              "dcp.ccval", FT_UINT8, BASE_DEC,  NULL, 0x0,
1014                   "", HFILL }},
1015
1016                 { &hf_dcp_cscov,
1017                 { "Checksum Coverage",  "dcp.cscov", FT_UINT8, BASE_DEC,  NULL, 0x0,
1018                   "", HFILL }},
1019
1020                 { &hf_dcp_checksum_bad,
1021                 { "Bad Checksum",       "dcp.checksum_bad", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1022                   "", HFILL }},
1023
1024                 { &hf_dcp_checksum,
1025                 { "Checksum",           "dcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1026                   "", HFILL }},
1027
1028                 { &hf_dcp_res1,
1029                 { "Reserved",           "dcp.res1", FT_UINT8, BASE_HEX, NULL, 0x0,
1030                   "", HFILL }},
1031
1032                 { &hf_dcp_res2,
1033                 { "Reserved",           "dcp.res2", FT_UINT8, BASE_HEX, NULL, 0x0,
1034                   "", HFILL }},
1035
1036                 { &hf_dcp_type,
1037                 { "Type",               "dcp.type", FT_UINT8, BASE_DEC, VALS(dcp_packet_type_vals), 0x0,
1038                   "", HFILL }},
1039
1040                 { &hf_dcp_x,
1041                 { "Extended Sequence Numbers", "dcp.x", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1042                   "", HFILL }},
1043
1044                 { &hf_dcp_seq,
1045                 { "Sequence Number",    "dcp.seq", FT_UINT64, BASE_DEC, NULL, 0x0,
1046                   "", HFILL }},
1047
1048                 { &hf_dcp_ack_res,
1049                 { "Reserved",           "dcp.ack_res", FT_UINT16, BASE_HEX, NULL, 0x0,
1050                   "", HFILL }},
1051
1052                 { &hf_dcp_ack,
1053                 { "Acknowledgement Number", "dcp.ack", FT_UINT64, BASE_DEC, NULL, 0x0,
1054                   "", HFILL }},
1055
1056                 { &hf_dcp_service_code,
1057                 { "Service Code", "dcp.service_code", FT_UINT32, BASE_DEC, NULL, 0x0,
1058                   "", HFILL }},
1059
1060                 { &hf_dcp_reset_code,
1061                 { "Reset Code", "dcp.reset_code", FT_UINT8, BASE_DEC, VALS(dcp_reset_code_vals), 0x0,
1062                   "", HFILL }},
1063
1064                 { &hf_dcp_data1,
1065                 { "Data 1",     "dcp.data1", FT_UINT8, BASE_DEC, NULL, 0x0,
1066                   "", HFILL }},
1067
1068                 { &hf_dcp_data2,
1069                 { "Data 2",     "dcp.data2", FT_UINT8, BASE_DEC, NULL, 0x0,
1070                   "", HFILL }},
1071
1072                 { &hf_dcp_data3,
1073                 { "Data 3",     "dcp.data3", FT_UINT8, BASE_DEC, NULL, 0x0,
1074                   "", HFILL }},
1075
1076                 { &hf_dcp_option_type,
1077                 { "Option Type",     "dcp.option_type", FT_UINT8, BASE_DEC, NULL, 0x0,
1078                   "", HFILL }},
1079
1080                 { &hf_dcp_feature_number,
1081                 { "Feature Number",   "dcp.feature_number", FT_UINT8, BASE_DEC, NULL, 0x0,
1082                   "", HFILL }},
1083
1084                 { &hf_dcp_ndp_count,
1085                 { "NDP Count",   "dcp.ndp_count", FT_UINT32, BASE_DEC, NULL, 0x0,
1086                   "", HFILL }},
1087
1088                 { &hf_dcp_timestamp,
1089                 { "Timestamp",   "dcp.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0,
1090                   "", HFILL }},
1091
1092                 { &hf_dcp_timestamp_echo,
1093                 { "Timestamp Echo",   "dcp.timestamp_echo", FT_UINT32, BASE_DEC, NULL, 0x0,
1094                   "", HFILL }},
1095
1096                 { &hf_dcp_elapsed_time,
1097                 { "Elapsed Time",   "dcp.elapsed_time", FT_UINT32, BASE_DEC, NULL, 0x0,
1098                   "", HFILL }},
1099
1100                 { &hf_dcp_data_checksum,
1101                 { "Data Checksum",  "dcp.checksum_data", FT_UINT32, BASE_HEX, NULL, 0x0,
1102                   "", HFILL }},
1103
1104                 { &hf_dcp_malformed,
1105                 { "Malformed", "dcp.malformed", FT_BOOLEAN, BASE_DEC, NULL, 0x0,
1106                   "", HFILL }},
1107
1108                 { &hf_dcp_options,
1109                 { "Options", "dcp.options", FT_NONE, BASE_DEC, NULL, 0x0,
1110                   "DCP Options fields", HFILL }}
1111
1112         };
1113
1114         static gint *ett[] = {
1115                 &ett_dcp,
1116                 &ett_dcp_options
1117         };
1118
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));
1122
1123         /* subdissectors */
1124         dcp_subdissector_table = register_dissector_table("dcp.port", "DCP port", FT_UINT16, BASE_DEC);
1125         register_heur_dissector_list("dcp", &heur_subdissector_list);
1126
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);
1133
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);
1139
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);
1144 }
1145
1146 void proto_reg_handoff_dcp(void)
1147 {
1148         dissector_handle_t dcp_handle;
1149
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");
1154 }