Revert "Fixup: tvb_* -> tvb_captured"
[metze/wireshark/wip.git] / epan / dissectors / packet-dcc.c
1 /* packet-dcc.c
2  * Routines for Distributed Checksum Clearinghouse packet dissection
3  * DCC Home: http://www.rhyolite.com/anti-spam/dcc/
4  *
5  * Copyright 1999, Nathan Neulinger <nneul@umr.edu>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-tftp.c
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #include <glib.h>
31 #include <epan/packet.h>
32
33 #include <packet-dcc.h>
34
35 void proto_register_dcc(void);
36 void proto_reg_handoff_dcc(void);
37
38 static int proto_dcc = -1;
39 static int hf_dcc_len = -1;
40 static int hf_dcc_pkt_vers = -1;
41 static int hf_dcc_op = -1;
42 static int hf_dcc_clientid = -1;
43 static int hf_dcc_opnums_host = -1;
44 static int hf_dcc_opnums_pid = -1;
45 static int hf_dcc_opnums_report = -1;
46 static int hf_dcc_opnums_retrans = -1;
47
48 static int hf_dcc_signature = -1;
49 static int hf_dcc_max_pkt_vers = -1;
50 static int hf_dcc_qdelay_ms = -1;
51 static int hf_dcc_brand = -1;
52
53 static int hf_dcc_ck_type = -1;
54 static int hf_dcc_ck_len = -1;
55 static int hf_dcc_ck_sum = -1;
56
57 static int hf_dcc_date = -1;
58
59 static int hf_dcc_target = -1;
60
61 static int hf_dcc_adminop = -1;
62 static int hf_dcc_adminval = -1;
63 static int hf_dcc_floodop = -1;
64 static int hf_dcc_trace = -1;
65 static int hf_dcc_trace_admin = -1;
66 static int hf_dcc_trace_anon = -1;
67 static int hf_dcc_trace_client = -1;
68 static int hf_dcc_trace_rlim = -1;
69 static int hf_dcc_trace_query = -1;
70 static int hf_dcc_trace_ridc = -1;
71 static int hf_dcc_trace_flood = -1;
72
73 static gint ett_dcc = -1;
74 static gint ett_dcc_opnums = -1;
75 static gint ett_dcc_op = -1;
76 static gint ett_dcc_ck = -1;
77 static gint ett_dcc_trace = -1;
78
79 /* Utility macros */
80 #define D_SIGNATURE() \
81         proto_tree_add_item(dcc_optree, hf_dcc_signature, tvb, \
82                 offset, (int)sizeof(DCC_SIGNATURE), ENC_NA); \
83         offset += (int)sizeof(DCC_SIGNATURE);
84
85 #define D_LABEL(label,len) \
86         proto_tree_add_text(dcc_optree, tvb, offset, len, label); \
87         offset += len;
88
89 #define D_TEXT(label, endpad) { \
90         int next_offset,left; \
91         while (tvb_offset_exists(tvb, offset+endpad)) { \
92                 left = tvb_length_remaining(tvb,offset) - endpad; \
93                 tvb_find_line_end(tvb, offset, left, &next_offset, \
94                     FALSE); \
95                 proto_tree_add_text(dcc_optree, tvb, offset, \
96                         next_offset - offset, "%s: %s", \
97                         label, tvb_format_text(tvb, offset, next_offset - offset)); \
98                 offset = next_offset; \
99         } \
100 }
101
102
103 #define D_TARGET() \
104         proto_tree_add_item(dcc_tree, hf_dcc_target, tvb, \
105                 offset, (int)sizeof(DCC_TGTS), ENC_BIG_ENDIAN); \
106         offset += (int)sizeof(DCC_TGTS);
107
108 #define D_DATE() { \
109         nstime_t ts; \
110         ts.nsecs = 0; \
111         ts.secs = tvb_get_ntohl(tvb,offset); \
112         proto_tree_add_time(dcc_optree, hf_dcc_date, tvb, offset, 4, &ts); \
113         offset += 4; \
114 }
115
116
117 #define D_CHECKSUM() { \
118         proto_tree *cktree, *ckti; \
119         ckti = proto_tree_add_text(dcc_optree, tvb, offset, (int)sizeof(DCC_CK), \
120                 "Checksum - %s", val_to_str(tvb_get_guint8(tvb,offset), \
121                 dcc_cktype_vals, \
122                 "Unknown Type: %u")); \
123         cktree = proto_item_add_subtree(ckti, ett_dcc_ck); \
124         proto_tree_add_item(cktree, hf_dcc_ck_type, tvb, offset, 1, ENC_BIG_ENDIAN); \
125         offset += 1; \
126         proto_tree_add_item(cktree, hf_dcc_ck_len, tvb, offset, 1, ENC_BIG_ENDIAN); \
127         offset += 1; \
128         proto_tree_add_item(cktree, hf_dcc_ck_sum, tvb, offset, \
129                 (int)sizeof(DCC_SUM), ENC_NA); \
130         offset += (int)sizeof(DCC_SUM); \
131 }
132
133
134 /* Lookup string tables */
135 static const value_string dcc_op_vals[] = {
136         {DCC_OP_INVALID, "Invalid Op"},
137         {DCC_OP_NOP,    "No-Op"},
138         {DCC_OP_REPORT, "Report and Query"},
139         {DCC_OP_QUERY, "Query"},
140         {DCC_OP_QUERY_RESP, "Server Response"},
141         {DCC_OP_ADMN, "Admin"},
142         {DCC_OP_OK, "Ok"},
143         {DCC_OP_ERROR, "Server Failing"},
144         {DCC_OP_DELETE, "Delete Checksum(s)"},
145         {0, NULL}
146 };
147
148 static const value_string dcc_cktype_vals[] = {
149         {DCC_CK_INVALID, "Invalid/Deleted from DB when seen"},
150         {DCC_CK_IP,     "MD5 of binary source IPv6 address"},
151         {DCC_CK_ENV_FROM, "MD5 of envelope Mail From value"},
152         {DCC_CK_FROM, "MD5 of header From: line"},
153         {DCC_CK_SUB, "MD5 of substitute header line"},
154         {DCC_CK_MESSAGE_ID, "MD5 of header Message-ID: line"},
155         {DCC_CK_RECEIVED, "MD5 of last header Received: line"},
156         {DCC_CK_BODY, "MD5 of body"},
157         {DCC_CK_FUZ1, "MD5 of filtered body - FUZ1"},
158         {DCC_CK_FUZ2, "MD5 of filtered body - FUZ2"},
159         {DCC_CK_FUZ3, "MD5 of filtered body - FUZ3"},
160         {DCC_CK_FUZ4, "MD5 of filtered body - FUZ4"},
161         {DCC_CK_SRVR_ID, "hostname for server-ID check "},
162         {DCC_CK_ENV_TO, "MD5 of envelope Rcpt To value"},
163         {0, NULL},
164 };
165
166 static const value_string dcc_adminop_vals[] = {
167         {DCC_AOP_OK, "Never sent"},
168         {DCC_AOP_STOP, "Stop Gracefully"},
169         {DCC_AOP_NEW_IDS, "Load keys and client IDs"},
170         {DCC_AOP_FLOD, "Flood control"},
171         {DCC_AOP_DB_UNLOCK, "Start Switch to new database"},
172         {DCC_AOP_DB_NEW, "Finish Switch to new database"},
173         {DCC_AOP_STATS, "Return counters"},
174         {DCC_AOP_STATS_CLEAR, "Return and zero counters"},
175         {DCC_AOP_TRACE_ON, "Enable tracing"},
176         {DCC_AOP_TRACE_OFF, "Disable tracing"},
177         {DCC_AOP_CUR_CLIENTS, "List clients"},
178         {0, NULL},
179 };
180
181 static const value_string dcc_target_vals[] = {
182         {DCC_TGTS_TOO_MANY, "Targets (>= 16777200)"},
183         {DCC_TGTS_OK, "Certified not spam"},
184         {DCC_TGTS_OK2, "Half certified not spam"},
185         {DCC_TGTS_DEL, "Deleted checksum"},
186         {DCC_TGTS_INVALID, "Invalid"},
187         {0, NULL},
188 };
189
190 static const value_string dcc_floodop_vals[] = {
191         {DCC_AOP_FLOD_CHECK, "Check"},
192         {DCC_AOP_FLOD_SHUTDOWN, "Shutdown"},
193         {DCC_AOP_FLOD_HALT, "Halt"},
194         {DCC_AOP_FLOD_RESUME, "Resume"},
195         {DCC_AOP_FLOD_REWIND, "Rewind"},
196         {DCC_AOP_FLOD_LIST, "List"},
197         {DCC_AOP_FLOD_STATS, "Stats"},
198         {DCC_AOP_FLOD_STATS_CLEAR, "Clear Stats"},
199         {0,NULL},
200 };
201
202 static gboolean
203 dissect_dcc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
204 {
205         proto_tree      *dcc_tree, *dcc_optree, *dcc_opnumtree, *ti;
206         proto_tree *dcc_tracetree;
207         int offset = 0;
208         int client_is_le = 0;
209         int op = 0;
210         int i, is_response;
211
212         if (pinfo->srcport != DCC_PORT && pinfo->destport != DCC_PORT) {
213                 /* Not the right port - not a DCC packet. */
214                 return FALSE;
215         }
216
217         /* get at least a full packet structure */
218         if ( tvb_length(tvb) < sizeof(DCC_HDR) ) {
219                 /* Doesn't have enough bytes to contain packet header. */
220                 return FALSE;
221         }
222
223         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCC");
224
225         offset = 0;
226         is_response = pinfo->srcport == DCC_PORT;
227
228         col_add_fstr(pinfo->cinfo, COL_INFO,
229                 "%s: %s",
230                 is_response ? "Response" : "Request",
231                 val_to_str(tvb_get_guint8(tvb, offset+3),
232                          dcc_op_vals, "Unknown Op: %u")
233         );
234
235         if (tree) {
236                 ti = proto_tree_add_item(tree, proto_dcc, tvb, offset, -1,
237                         ENC_NA);
238                 dcc_tree = proto_item_add_subtree(ti, ett_dcc);
239
240                 proto_tree_add_item(dcc_tree, hf_dcc_len, tvb,
241                         offset, 2, ENC_BIG_ENDIAN);
242
243                 if ( tvb_length(tvb) < tvb_get_ntohs(tvb, offset)) {
244                         /* Doesn't have number of bytes that header claims. */
245                         proto_tree_add_text(dcc_tree, tvb, offset, 2, "Error - packet is shorter than header claims!");
246                 }
247                 offset += 2;
248
249                 proto_tree_add_item(dcc_tree, hf_dcc_pkt_vers, tvb,
250                         offset, 1, ENC_BIG_ENDIAN);
251                 offset += 1;
252
253                 op = tvb_get_guint8(tvb, offset);
254                 proto_tree_add_item(dcc_tree, hf_dcc_op, tvb,
255                         offset, 1, ENC_BIG_ENDIAN);
256                 offset += 1;
257
258                 proto_tree_add_item(dcc_tree, hf_dcc_clientid, tvb,
259                         offset, 4, ENC_BIG_ENDIAN);
260                 offset += 4;
261
262                 ti = proto_tree_add_text(dcc_tree, tvb, offset, -1, "Operation Numbers (Opaque to Server)");
263                 dcc_opnumtree = proto_item_add_subtree(ti, ett_dcc_opnums);
264
265                 /* Note - these are indeterminate - they are sortof considered opaque to the client */
266                 /* Make some attempt to figure out if this data is little endian, not guaranteed to be
267                 correct if connection went through a firewall or similar. */
268
269                 /* Very hokey check - if all three of pid/report/retrans look like little-endian
270                         numbers, host is probably little endian. Probably innacurate on super-heavily-used
271                         DCC clients though. This should be good enough for now. */
272                 client_is_le = ( (tvb_get_guint8(tvb, offset+4) | tvb_get_guint8(tvb, offset+4)) &&
273                                                  (tvb_get_guint8(tvb, offset+8) | tvb_get_guint8(tvb, offset+9)) &&
274                                                  (tvb_get_guint8(tvb, offset+12) | tvb_get_guint8(tvb, offset+13)) );
275
276                 proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_host, tvb,
277                         offset, 4, client_is_le);
278                 offset += 4;
279
280                 proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_pid, tvb,
281                         offset, 4, client_is_le);
282                 offset += 4;
283
284                 proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_report, tvb,
285                         offset, 4, client_is_le);
286                 offset += 4;
287
288                 proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_retrans, tvb,
289                         offset, 4, client_is_le);
290                 offset += 4;
291
292                 ti = proto_tree_add_text(dcc_tree, tvb, offset, -1, "Operation: %s",
293                         val_to_str(op, dcc_op_vals, "Unknown Op: %u"));
294                 dcc_optree = proto_item_add_subtree(ti, ett_dcc_op);
295
296                 switch(op) {
297                         case DCC_OP_NOP:
298                                 D_SIGNATURE();
299                                 break;
300
301                         case DCC_OP_REPORT:
302                                 D_TARGET();
303                                 for (i=0; i<=DCC_QUERY_MAX &&
304                                         tvb_bytes_exist(tvb, offset+(int)sizeof(DCC_SIGNATURE),1); i++)
305                                 {
306                                         D_CHECKSUM();
307                                 }
308                                 D_SIGNATURE();
309                                 break;
310
311                         case DCC_OP_QUERY_RESP:
312                                 for (i=0; i<=DCC_QUERY_MAX &&
313                                         tvb_bytes_exist(tvb, offset+(int)sizeof(DCC_SIGNATURE),1); i++)
314                                 {
315                                         D_TARGET();
316                                 }
317                                 D_SIGNATURE();
318                                 break;
319
320                         case DCC_OP_ADMN:
321                                 if ( is_response )
322                                 {
323                                         int left_local = tvb_length_remaining(tvb, offset) -
324                                                 (int)sizeof(DCC_SIGNATURE);
325                                         if ( left_local == sizeof(DCC_ADMN_RESP_CLIENTS) )
326                                         {
327                                                 D_LABEL("Addr", 16);
328                                                 D_LABEL("Id", (int)sizeof(DCC_CLNT_ID));
329                                                 D_LABEL("Last Used", 4);
330                                                 D_LABEL("Requests", 4);
331                                         }
332                                         else
333                                         {
334                                                 D_TEXT("Response Text", (int)sizeof(DCC_SIGNATURE));
335                                         }
336                                         D_SIGNATURE();
337                                 }
338                                 else
339                                 {
340                                         int aop;
341
342                                         D_DATE();
343
344                                         aop = tvb_get_guint8(tvb, offset+4);
345                                         proto_tree_add_item(dcc_optree, hf_dcc_adminop, tvb, offset+4,
346                                                 1, ENC_BIG_ENDIAN);
347                                         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
348                                                 val_to_str(tvb_get_guint8(tvb,offset+4),
349                                                 dcc_adminop_vals, "Unknown (%u)"));
350
351                                         if (aop == DCC_AOP_TRACE_ON || aop == DCC_AOP_TRACE_OFF )
352                                         {
353                                                 ti = proto_tree_add_item(dcc_optree, hf_dcc_trace, tvb, offset,
354                                                         4, ENC_BIG_ENDIAN);
355                                                 dcc_tracetree = proto_item_add_subtree(ti, ett_dcc_trace);
356                                                 proto_tree_add_item(dcc_tracetree, hf_dcc_trace_admin, tvb, offset, 4, ENC_BIG_ENDIAN);
357                                                 proto_tree_add_item(dcc_tracetree, hf_dcc_trace_anon, tvb, offset, 4, ENC_BIG_ENDIAN);
358                                                 proto_tree_add_item(dcc_tracetree, hf_dcc_trace_client, tvb, offset, 4, ENC_BIG_ENDIAN);
359                                                 proto_tree_add_item(dcc_tracetree, hf_dcc_trace_rlim, tvb, offset, 4, ENC_BIG_ENDIAN);
360                                                 proto_tree_add_item(dcc_tracetree, hf_dcc_trace_query, tvb, offset, 4, ENC_BIG_ENDIAN);
361                                                 proto_tree_add_item(dcc_tracetree, hf_dcc_trace_ridc, tvb, offset, 4, ENC_BIG_ENDIAN);
362                                                 proto_tree_add_item(dcc_tracetree, hf_dcc_trace_flood, tvb, offset, 4, ENC_BIG_ENDIAN);
363                                         }
364                                         else if ( aop == DCC_AOP_FLOD )
365                                         {
366                                                 proto_tree_add_item(dcc_optree, hf_dcc_floodop,
367                                                         tvb, offset, 4, ENC_BIG_ENDIAN);
368                                                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
369                                                         val_to_str(tvb_get_ntohl(tvb,offset),
370                                                         dcc_floodop_vals, "Unknown (%u)"));
371                                         }
372                                         else
373                                         {
374                                                 proto_tree_add_item(dcc_optree, hf_dcc_adminval,
375                                                         tvb, offset, 4, ENC_BIG_ENDIAN);
376                                         }
377                                         offset += 4;
378
379                                         offset += 1; /* admin op we did in reverse order */
380                                         D_LABEL("Pad", 3);
381                                         D_SIGNATURE();
382                                 }
383                                 break;
384
385                         case DCC_OP_OK:
386                                 proto_tree_add_item(dcc_optree, hf_dcc_max_pkt_vers, tvb,
387                                         offset, 1, ENC_BIG_ENDIAN);
388                                 offset += 1;
389
390                                 D_LABEL("Unused", 1);
391
392                                 proto_tree_add_item(dcc_optree, hf_dcc_qdelay_ms, tvb,
393                                         offset, 2, ENC_BIG_ENDIAN);
394                                 offset += 2;
395
396                                 proto_tree_add_item(dcc_optree, hf_dcc_brand, tvb,
397                                         offset, (int)sizeof(DCC_BRAND), ENC_ASCII|ENC_NA);
398                                 offset += (int)sizeof(DCC_BRAND);
399
400                                 D_SIGNATURE();
401                                 break;
402
403                         default:
404                                 /* do nothing */
405                                 break;
406                 }
407         }
408
409         return TRUE;
410 }
411
412 void
413 proto_register_dcc(void)
414 {
415         static hf_register_info hf[] = {
416                         { &hf_dcc_len, {
417                                 "Packet Length", "dcc.len", FT_UINT16, BASE_DEC,
418                                 NULL, 0, NULL, HFILL }},
419
420                         { &hf_dcc_pkt_vers, {
421                                 "Packet Version", "dcc.pkt_vers", FT_UINT16, BASE_DEC,
422                                 NULL, 0, NULL, HFILL }},
423
424                         { &hf_dcc_op, {
425                                 "Operation Type", "dcc.op", FT_UINT8, BASE_DEC,
426                                 VALS(dcc_op_vals), 0, NULL, HFILL }},
427
428                         { &hf_dcc_clientid, {
429                                 "Client ID", "dcc.clientid", FT_UINT32, BASE_DEC,
430                                 NULL, 0, NULL, HFILL }},
431
432                         { &hf_dcc_opnums_host, {
433                                 "Host", "dcc.opnums.host", FT_UINT32, BASE_DEC,
434                                 NULL, 0, NULL, HFILL }},
435
436                         { &hf_dcc_opnums_pid, {
437                                 "Process ID", "dcc.opnums.pid", FT_UINT32, BASE_DEC,
438                                 NULL, 0, NULL, HFILL }},
439
440                         { &hf_dcc_opnums_report, {
441                                 "Report", "dcc.opnums.report", FT_UINT32, BASE_DEC,
442                                 NULL, 0, NULL, HFILL }},
443
444                         { &hf_dcc_opnums_retrans, {
445                                 "Retransmission", "dcc.opnums.retrans", FT_UINT32, BASE_DEC,
446                                 NULL, 0, NULL, HFILL }},
447
448                         { &hf_dcc_signature, {
449                                 "Signature", "dcc.signature", FT_BYTES, BASE_NONE,
450                                 NULL, 0, NULL, HFILL }},
451
452                         { &hf_dcc_max_pkt_vers, {
453                                 "Maximum Packet Version", "dcc.max_pkt_vers", FT_UINT8, BASE_DEC,
454                                 NULL, 0, NULL, HFILL }},
455
456                         { &hf_dcc_qdelay_ms, {
457                                 "Client Delay", "dcc.qdelay_ms", FT_UINT16, BASE_DEC,
458                                 NULL, 0, NULL, HFILL }},
459
460                         { &hf_dcc_brand, {
461                                 "Server Brand", "dcc.brand", FT_STRING, BASE_NONE,
462                                 NULL, 0, NULL, HFILL }},
463
464                         { &hf_dcc_ck_type, {
465                                 "Type", "dcc.checksum.type", FT_UINT8, BASE_DEC,
466                                 VALS(dcc_cktype_vals), 0, "Checksum Type", HFILL }},
467
468                         { &hf_dcc_ck_len, {
469                                 "Length", "dcc.checksum.length", FT_UINT8, BASE_DEC,
470                                 NULL, 0, "Checksum Length", HFILL }},
471
472                         { &hf_dcc_ck_sum, {
473                                 "Sum", "dcc.checksum.sum", FT_BYTES, BASE_NONE,
474                                 NULL, 0, "Checksum", HFILL }},
475
476                         { &hf_dcc_target, {
477                                 "Target", "dcc.target", FT_UINT32, BASE_HEX,
478                                 VALS(dcc_target_vals), 0, NULL, HFILL }},
479
480                         { &hf_dcc_date, {
481                                 "Date", "dcc.date", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
482                                 NULL, 0, NULL, HFILL }},
483
484                         { &hf_dcc_adminop, {
485                                 "Admin Op", "dcc.adminop", FT_UINT8, BASE_DEC,
486                                 VALS(dcc_adminop_vals), 0, NULL, HFILL }},
487
488                         { &hf_dcc_adminval, {
489                                 "Admin Value", "dcc.adminval", FT_UINT32, BASE_DEC,
490                                 NULL, 0, NULL, HFILL }},
491
492                         { &hf_dcc_trace, {
493                                 "Trace Bits", "dcc.trace", FT_UINT32, BASE_HEX,
494                                 NULL, 0, NULL, HFILL }},
495
496                         { &hf_dcc_trace_admin, {
497                                 "Admin Requests", "dcc.trace.admin", FT_BOOLEAN, 32,
498                                 NULL, 0x00000001, NULL, HFILL }},
499
500                         { &hf_dcc_trace_anon, {
501                                 "Anonymous Requests", "dcc.trace.anon", FT_BOOLEAN, 32,
502                                 NULL, 0x00000002, NULL, HFILL }},
503
504                         { &hf_dcc_trace_client, {
505                                 "Authenticated Client Requests", "dcc.trace.client", FT_BOOLEAN, 32,
506                                 NULL, 0x00000004, NULL, HFILL }},
507
508                         { &hf_dcc_trace_rlim, {
509                                 "Rate-Limited Requests", "dcc.trace.rlim", FT_BOOLEAN, 32,
510                                 NULL, 0x00000008, NULL, HFILL }},
511
512                         { &hf_dcc_trace_query, {
513                                 "Queries and Reports", "dcc.trace.query", FT_BOOLEAN, 32,
514                                 NULL, 0x00000010, NULL, HFILL }},
515
516                         { &hf_dcc_trace_ridc, {
517                                 "RID Cache Messages", "dcc.trace.ridc", FT_BOOLEAN, 32,
518                                 NULL, 0x00000020, NULL, HFILL }},
519
520                         { &hf_dcc_trace_flood, {
521                                 "Input/Output Flooding", "dcc.trace.flood", FT_BOOLEAN, 32,
522                                 NULL, 0x00000040, NULL, HFILL }},
523
524                         { &hf_dcc_floodop, {
525                                 "Flood Control Operation", "dcc.floodop", FT_UINT32, BASE_DEC,
526                                 VALS(dcc_floodop_vals), 0, NULL, HFILL }},
527
528         };
529         static gint *ett[] = {
530                 &ett_dcc,
531                 &ett_dcc_op,
532                 &ett_dcc_ck,
533                 &ett_dcc_opnums,
534                 &ett_dcc_trace,
535         };
536
537         proto_dcc = proto_register_protocol("Distributed Checksum Clearinghouse protocol",
538             "DCC", "dcc");
539
540         proto_register_field_array(proto_dcc, hf, array_length(hf));
541
542         proto_register_subtree_array(ett, array_length(ett));
543 }
544
545 void
546 proto_reg_handoff_dcc(void)
547 {
548         heur_dissector_add("udp", dissect_dcc, proto_dcc);
549 }