From Duncan Salerno:
[obnox/wireshark/wip.git] / epan / dissectors / packet-frame.c
1 /* packet-frame.c
2  *
3  * Top-most dissector. Decides dissector based on Wiretap Encapsulation Type.
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 2000 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef _MSC_VER
31 #include <windows.h>
32 #endif
33
34
35 #include <glib.h>
36 #include <epan/packet.h>
37 #include <epan/timestamp.h>
38 #include <epan/tvbuff.h>
39 #include "packet-frame.h"
40 #include <epan/prefs.h>
41 #include <epan/tap.h>
42 #include <epan/expert.h>
43 #include <epan/crypt/crypt-md5.h>
44
45 #include "color.h"
46 #include "color_filters.h"
47
48 int proto_frame = -1;
49 int hf_frame_arrival_time = -1;
50 static int hf_frame_time_invalid = -1;
51 static int hf_frame_time_delta = -1;
52 static int hf_frame_time_delta_displayed = -1;
53 static int hf_frame_time_relative = -1;
54 int hf_frame_number = -1;
55 int hf_frame_packet_len = -1; /* Deprecated in favor of hf_frame_len */
56 int hf_frame_len = -1;
57 int hf_frame_capture_len = -1;
58 static int hf_frame_p2p_dir = -1;
59 static int hf_frame_file_off = -1;
60 static int hf_frame_md5_hash = -1;
61 static int hf_frame_marked = -1;
62 static int hf_frame_ref_time = -1;
63 static int hf_link_number = -1;
64 static int hf_frame_protocols = -1;
65 static int hf_frame_color_filter_name = -1;
66 static int hf_frame_color_filter_text = -1;
67
68 static int proto_short = -1;
69 int proto_malformed = -1;
70 static int proto_unreassembled = -1;
71
72 static gint ett_frame = -1;
73
74 static int frame_tap = -1;
75
76 static dissector_handle_t data_handle;
77 static dissector_handle_t docsis_handle;
78
79 /* Preferences */
80 static gboolean show_file_off = FALSE;
81 static gboolean force_docsis_encap;
82 static gboolean generate_md5_hash = FALSE;
83
84 static const value_string p2p_dirs[] = {
85         { P2P_DIR_SENT, "Sent" },
86         { P2P_DIR_RECV, "Received" },
87         { 0, NULL }
88 };
89
90 dissector_table_t wtap_encap_dissector_table;
91
92 static GSList *frame_end_routines = NULL;
93
94 /*
95  * Routine used to register frame end routine.  The routine should only
96  * be registred when the dissector is used in the frame, not in the
97  * proto_register_XXX function.
98  */
99 void
100 register_frame_end_routine(void (*func)(void))
101 {
102         frame_end_routines = g_slist_append(frame_end_routines, (gpointer)func);
103 }
104
105 typedef void (*void_func_t)(void);
106
107 static void
108 call_frame_end_routine(gpointer routine, gpointer dummy _U_)
109 {
110         void_func_t func = (void_func_t)routine;
111         (*func)();
112 }
113
114 static void
115 dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
116 {
117         proto_tree      *fh_tree=NULL;
118         proto_item      *volatile ti = NULL;
119         nstime_t        ts;
120         int             cap_len = 0, frame_len = 0;
121         proto_tree      *volatile tree;
122         proto_item  *item;
123         guint32 frame_number;
124
125         frame_number=pinfo->fd->num; /* dummy so that the buildbot crashdumps
126                                         will show the packetnumber where the
127                                         crash occurred.
128                                      */
129         tree=parent_tree;
130
131         pinfo->current_proto = "Frame";
132
133         if (pinfo->pseudo_header != NULL) {
134                 switch (pinfo->fd->lnk_t) {
135
136                 case WTAP_ENCAP_WFLEET_HDLC:
137                 case WTAP_ENCAP_CHDLC_WITH_PHDR:
138                 case WTAP_ENCAP_PPP_WITH_PHDR:
139                 case WTAP_ENCAP_SDLC:
140                 case WTAP_ENCAP_BLUETOOTH_H4:
141                 case WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR:
142                         pinfo->p2p_dir = pinfo->pseudo_header->p2p.sent ?
143                             P2P_DIR_SENT : P2P_DIR_RECV;
144                         break;
145
146                 case WTAP_ENCAP_BLUETOOTH_HCI:
147                         pinfo->p2p_dir = pinfo->pseudo_header->bthci.sent ?
148                             P2P_DIR_SENT : P2P_DIR_RECV;
149                         break;
150
151                 case WTAP_ENCAP_LAPB:
152                 case WTAP_ENCAP_FRELAY_WITH_PHDR:
153                         pinfo->p2p_dir =
154                             (pinfo->pseudo_header->x25.flags & FROM_DCE) ?
155                             P2P_DIR_RECV : P2P_DIR_SENT;
156                         break;
157
158                 case WTAP_ENCAP_ISDN:
159                         pinfo->p2p_dir = pinfo->pseudo_header->isdn.uton ?
160                             P2P_DIR_SENT : P2P_DIR_RECV;
161                         break;
162
163                 case WTAP_ENCAP_LINUX_LAPD:
164                         pinfo->p2p_dir = (pinfo->pseudo_header->lapd.pkttype == 3 ||
165                                 pinfo->pseudo_header->lapd.pkttype == 4) ?
166                                 P2P_DIR_SENT : P2P_DIR_RECV;
167                         break;
168
169                 case WTAP_ENCAP_MTP2_WITH_PHDR:
170                         pinfo->p2p_dir = pinfo->pseudo_header->mtp2.sent ?
171                             P2P_DIR_SENT : P2P_DIR_RECV;
172                         pinfo->link_number  = pinfo->pseudo_header->mtp2.link_number;
173                         pinfo->annex_a_used = pinfo->pseudo_header->mtp2.annex_a_used;
174                         break;
175
176                 case WTAP_ENCAP_GSM_UM:
177                         pinfo->p2p_dir = pinfo->pseudo_header->gsm_um.uplink ?
178                             P2P_DIR_SENT : P2P_DIR_RECV;
179                         break;
180
181                 }
182         }
183
184         /* Put in frame header information. */
185         if (tree) {
186           cap_len = tvb_length(tvb);
187           frame_len = tvb_reported_length(tvb);
188
189           ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, -1,
190             "Frame %u (%u bytes on wire, %u bytes captured)", pinfo->fd->num, frame_len, cap_len);
191
192           fh_tree = proto_item_add_subtree(ti, ett_frame);
193         }
194
195         /* if FRAME is not referenced from any filters we dont need to worry about
196            generating any tree items.  We must do this after we created the actual
197            protocol above so that proto hier stat still works though.
198         */
199         if(!proto_field_is_referenced(tree, proto_frame)){
200                 tree=NULL;
201                 fh_tree = NULL;
202         }
203
204
205         if (fh_tree) {
206           ts = pinfo->fd->abs_ts;
207
208           proto_tree_add_time(fh_tree, hf_frame_arrival_time, tvb,
209                 0, 0, &ts);
210       if(ts.nsecs < 0 || ts.nsecs >= 1000000000) {
211             item = proto_tree_add_none_format(fh_tree, hf_frame_time_invalid, tvb,
212                   0, 0, "Arrival Time: Fractional second %09ld is invalid, the valid range is 0-1000000000", (long) ts.nsecs);
213             PROTO_ITEM_SET_GENERATED(item);
214                 expert_add_info_format(pinfo, item, PI_MALFORMED, PI_WARN, "Arrival Time: Fractional second out of range (0-1000000000)");
215       }
216
217           ts = pinfo->fd->del_cap_ts;
218
219           item = proto_tree_add_time(fh_tree, hf_frame_time_delta, tvb,
220                 0, 0, &ts);
221           PROTO_ITEM_SET_GENERATED(item);
222
223           ts = pinfo->fd->del_dis_ts;
224
225           item = proto_tree_add_time(fh_tree, hf_frame_time_delta_displayed, tvb,
226                 0, 0, &ts);
227           PROTO_ITEM_SET_GENERATED(item);
228
229           ts = pinfo->fd->rel_ts;
230
231           item = proto_tree_add_time(fh_tree, hf_frame_time_relative, tvb,
232                 0, 0, &ts);
233           PROTO_ITEM_SET_GENERATED(item);
234
235           proto_tree_add_uint(fh_tree, hf_frame_number, tvb,
236                 0, 0, pinfo->fd->num);
237
238           /* Deprecated in favor of hf_frame_len */
239           item = proto_tree_add_uint_format(fh_tree, hf_frame_packet_len, tvb,
240                 0, 0, frame_len, "Packet Length: %d byte%s", frame_len,
241                 plurality(frame_len, "", "s"));
242           PROTO_ITEM_SET_HIDDEN(item);
243
244           proto_tree_add_uint_format(fh_tree, hf_frame_len, tvb,
245                 0, 0, frame_len, "Frame Length: %d byte%s", frame_len,
246                 plurality(frame_len, "", "s"));
247
248           proto_tree_add_uint_format(fh_tree, hf_frame_capture_len, tvb,
249                 0, 0, cap_len, "Capture Length: %d byte%s", cap_len,
250                 plurality(cap_len, "", "s"));
251
252           /* we are going to be using proto_item_append_string() on
253            * hf_frame_protocols, and we must therefore disable the
254            * TRY_TO_FAKE_THIS_ITEM() optimisation for the tree by
255            * setting it as visible.
256            *
257            * See proto.h for details.
258            */
259           proto_tree_set_visible(fh_tree, TRUE);
260
261           if (generate_md5_hash) {
262                   const guint8 *cp;
263                   md5_state_t md_ctx;
264                   md5_byte_t digest[16];
265                   gchar *digest_string;
266
267                   cp = tvb_get_ptr(tvb, 0, cap_len);
268
269                   md5_init(&md_ctx);
270                   md5_append(&md_ctx, cp, cap_len);
271                   md5_finish(&md_ctx, digest);
272
273                   digest_string = bytestring_to_str(digest, 16, '\0');
274                   ti = proto_tree_add_string(fh_tree, hf_frame_md5_hash, tvb, 0, 0, digest_string);
275                   PROTO_ITEM_SET_GENERATED(ti);
276           }
277
278           if(pinfo->fd->flags.ref_time){
279                 ti = proto_tree_add_item(fh_tree, hf_frame_ref_time, tvb, 0, 0, FALSE);
280             PROTO_ITEM_SET_GENERATED(ti);
281           }
282
283           ti = proto_tree_add_boolean(fh_tree, hf_frame_marked, tvb, 0, 0,pinfo->fd->flags.marked);
284           PROTO_ITEM_SET_GENERATED(ti);
285
286           ti = proto_tree_add_string(fh_tree, hf_frame_protocols, tvb,
287                 0, 0, "");
288           PROTO_ITEM_SET_GENERATED(ti);
289           pinfo->layer_names = g_string_new("");
290
291           /* Check for existences of P2P pseudo header */
292           if (pinfo->p2p_dir != P2P_DIR_UNKNOWN) {
293                   proto_tree_add_uint(fh_tree, hf_frame_p2p_dir, tvb,
294                                   0, 0, pinfo->p2p_dir);
295           }
296
297           /* Check for existences of MTP2 link number */
298           if ((pinfo->pseudo_header != NULL ) && (pinfo->fd->lnk_t == WTAP_ENCAP_MTP2_WITH_PHDR)) {
299                   proto_tree_add_uint(fh_tree, hf_link_number, tvb,
300                                   0, 0, pinfo->link_number);
301           }
302
303           if (show_file_off) {
304                   proto_tree_add_int64_format(fh_tree, hf_frame_file_off, tvb,
305                                   0, 0, pinfo->fd->file_off,
306                                   "File Offset: %" G_GINT64_MODIFIER "d (0x%" G_GINT64_MODIFIER "x)",
307                                   pinfo->fd->file_off, pinfo->fd->file_off);
308           }
309
310       if(pinfo->fd->color_filter != NULL) {
311           color_filter_t *color_filter = pinfo->fd->color_filter;
312               item = proto_tree_add_string(fh_tree, hf_frame_color_filter_name, tvb,
313                     0, 0, color_filter->filter_name);
314               PROTO_ITEM_SET_GENERATED(item);
315               item = proto_tree_add_string(fh_tree, hf_frame_color_filter_text, tvb,
316                     0, 0, color_filter->filter_text);
317               PROTO_ITEM_SET_GENERATED(item);
318       }
319     } else {
320       if(pinfo->fd->abs_ts.nsecs < 0 || pinfo->fd->abs_ts.nsecs >= 1000000000) {
321                 expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_WARN, "Arrival Time: Fractional second out of range (0-1000000000)");
322       }
323     }
324
325     /* Portable Exception Handling to trap Wireshark specific exceptions like BoundsError exceptions */
326         TRY {
327 #ifdef _MSC_VER
328     /* Win32: Visual-C Structured Exception Handling (SEH) to trap hardware exceptions like memory access violations */
329     /* (a running debugger will be called before the except part below) */
330     __try {
331 #endif
332         if ((force_docsis_encap) && (docsis_handle)) {
333             call_dissector(docsis_handle, tvb, pinfo, parent_tree);
334         } else {
335             if (!dissector_try_port(wtap_encap_dissector_table, pinfo->fd->lnk_t,
336                 tvb, pinfo, parent_tree)) {
337
338                         if (check_col(pinfo->cinfo, COL_PROTOCOL))
339                                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UNKNOWN");
340                         if (check_col(pinfo->cinfo, COL_INFO))
341                                 col_add_fstr(pinfo->cinfo, COL_INFO, "WTAP_ENCAP = %u",
342                                     pinfo->fd->lnk_t);
343                         call_dissector(data_handle,tvb, pinfo, parent_tree);
344                 }
345         }
346 #ifdef _MSC_VER
347     } __except(TRUE /* handle all exceptions */) {
348         switch(GetExceptionCode()) {
349         case(STATUS_ACCESS_VIOLATION):
350                     show_exception(tvb, pinfo, parent_tree, DissectorError,
351                 "STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
352             break;
353         case(STATUS_INTEGER_DIVIDE_BY_ZERO):
354                     show_exception(tvb, pinfo, parent_tree, DissectorError,
355                 "STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
356             break;
357         case(STATUS_STACK_OVERFLOW):
358                     show_exception(tvb, pinfo, parent_tree, DissectorError,
359                 "STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
360             /* XXX - this will have probably corrupted the stack, which makes problems later in the exception code */
361             break;
362         /* XXX - add other hardware exception codes as required */
363         default:
364                     show_exception(tvb, pinfo, parent_tree, DissectorError,
365                 g_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
366         }
367     }
368 #endif
369         }
370         CATCH(OutOfMemoryError) {
371                 RETHROW;
372         }
373         CATCH_ALL {
374                 show_exception(tvb, pinfo, parent_tree, EXCEPT_CODE, GET_MESSAGE);
375         }
376         ENDTRY;
377
378         if (tree && pinfo->layer_names) {
379                 proto_item_append_string(ti, pinfo->layer_names->str);
380                 g_string_free(pinfo->layer_names, TRUE);
381                 pinfo->layer_names = NULL;
382         }
383
384         /*  Call postdissectors if we have any (while trying to avoid another
385          *  TRY/CATCH)
386          */
387         if (have_postdissector()) {
388             TRY {
389 #ifdef _MSC_VER
390             /* Win32: Visual-C Structured Exception Handling (SEH) to trap hardware exceptions like memory access violations */
391             /* (a running debugger will be called before the except part below) */
392             __try {
393 #endif
394                 call_all_postdissectors(tvb, pinfo, parent_tree);
395 #ifdef _MSC_VER
396             } __except(TRUE /* handle all exceptions */) {
397                 switch(GetExceptionCode()) {
398                 case(STATUS_ACCESS_VIOLATION):
399                             show_exception(tvb, pinfo, parent_tree, DissectorError,
400                         "STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
401                     break;
402                 case(STATUS_INTEGER_DIVIDE_BY_ZERO):
403                             show_exception(tvb, pinfo, parent_tree, DissectorError,
404                         "STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
405                     break;
406                 case(STATUS_STACK_OVERFLOW):
407                             show_exception(tvb, pinfo, parent_tree, DissectorError,
408                         "STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
409                     /* XXX - this will have probably corrupted the stack, which makes problems later in the exception code */
410                     break;
411                 /* XXX - add other hardware exception codes as required */
412                 default:
413                             show_exception(tvb, pinfo, parent_tree, DissectorError,
414                         g_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
415                 }
416             }
417 #endif
418             }
419             CATCH(OutOfMemoryError) {
420                     RETHROW;
421             }
422             CATCH_ALL {
423                     show_exception(tvb, pinfo, parent_tree, EXCEPT_CODE, GET_MESSAGE);
424             }
425             ENDTRY;
426         }
427
428         tap_queue_packet(frame_tap, pinfo, NULL);
429
430
431         if (frame_end_routines) {
432                 g_slist_foreach(frame_end_routines, &call_frame_end_routine, NULL);
433                 g_slist_free(frame_end_routines);
434                 frame_end_routines = NULL;
435         }
436 }
437
438 void
439 show_exception(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
440     unsigned long exception, const char *exception_message)
441 {
442         static const char dissector_error_nomsg[] =
443             "Dissector writer didn't bother saying what the error was";
444         proto_item *item;
445
446
447         switch (exception) {
448
449         case ScsiBoundsError:
450                 if (check_col(pinfo->cinfo, COL_INFO))
451                         col_append_str(pinfo->cinfo, COL_INFO, "[SCSI transfer limited due to allocation_length too small]");
452                 /*item =*/ proto_tree_add_protocol_format(tree, proto_short, tvb, 0, 0,
453                                 "SCSI transfer limited due to allocation_length too small: %s truncated]", pinfo->current_proto);
454                 /* Don't record ScsiBoundsError exceptions as expert events - they merely
455                  * reflect a normal SCSI condition.
456                  * (any case where it's caused by something else is a bug). */
457                 /* expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Packet size limited");*/
458                 break;
459
460         case BoundsError:
461                 if (check_col(pinfo->cinfo, COL_INFO))
462                         col_append_str(pinfo->cinfo, COL_INFO, "[Packet size limited during capture]");
463                 /*item =*/ proto_tree_add_protocol_format(tree, proto_short, tvb, 0, 0,
464                                 "[Packet size limited during capture: %s truncated]", pinfo->current_proto);
465                 /* Don't record BoundsError exceptions as expert events - they merely
466                  * reflect a capture done with a snapshot length too short to capture
467                  * all of the packet
468                  * (any case where it's caused by something else is a bug). */
469                 /* expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Packet size limited");*/
470                 break;
471
472         case ReportedBoundsError:
473                 show_reported_bounds_error(tvb, pinfo, tree);
474                 break;
475
476         case DissectorError:
477                 if (check_col(pinfo->cinfo, COL_INFO))
478                         col_append_fstr(pinfo->cinfo, COL_INFO,
479                             "[Dissector bug, protocol %s: %s]",
480                             pinfo->current_proto,
481                             exception_message == NULL ?
482                                 dissector_error_nomsg : exception_message);
483                 item = proto_tree_add_protocol_format(tree, proto_malformed, tvb, 0, 0,
484                     "[Dissector bug, protocol %s: %s]",
485                     pinfo->current_proto,
486                     exception_message == NULL ?
487                         dissector_error_nomsg : exception_message);
488                 g_warning("Dissector bug, protocol %s, in packet %u: %s",
489                     pinfo->current_proto, pinfo->fd->num,
490                     exception_message == NULL ?
491                         dissector_error_nomsg : exception_message);
492                 expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR,
493                     "%s",
494                     exception_message == NULL ?
495                         dissector_error_nomsg : exception_message);
496                 break;
497
498         default:
499                 /* XXX - we want to know, if an unknown exception passed until here, don't we? */
500                 g_assert_not_reached();
501         }
502 }
503
504 void
505 show_reported_bounds_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
506 {
507         proto_item *item;
508
509         if (pinfo->fragmented) {
510                 /*
511                  * We were dissecting an unreassembled fragmented
512                  * packet when the exception was thrown, so the
513                  * problem isn't that the dissector expected
514                  * something but it wasn't in the packet, the
515                  * problem is that the dissector expected something
516                  * but it wasn't in the fragment we dissected.
517                  */
518                 if (check_col(pinfo->cinfo, COL_INFO))
519                         col_append_fstr(pinfo->cinfo, COL_INFO,
520                             "[Unreassembled Packet%s] ",
521                             pinfo->noreassembly_reason);
522                 item = proto_tree_add_protocol_format(tree, proto_unreassembled,
523                     tvb, 0, 0, "[Unreassembled Packet%s: %s]",
524                     pinfo->noreassembly_reason, pinfo->current_proto);
525                 expert_add_info_format(pinfo, item, PI_REASSEMBLE, PI_WARN, "Unreassembled Packet (Exception occurred)");
526         } else {
527                 if (check_col(pinfo->cinfo, COL_INFO))
528                         col_append_str(pinfo->cinfo, COL_INFO,
529                             "[Malformed Packet]");
530                 item = proto_tree_add_protocol_format(tree, proto_malformed,
531                     tvb, 0, 0, "[Malformed Packet: %s]", pinfo->current_proto);
532                 expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Malformed Packet (Exception occurred)");
533         }
534 }
535
536 void
537 proto_register_frame(void)
538 {
539         static hf_register_info hf[] = {
540                 { &hf_frame_arrival_time,
541                 { "Arrival Time",               "frame.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
542                         "Absolute time when this frame was captured", HFILL }},
543
544                 { &hf_frame_time_invalid,
545                 { "Arrival Timestamp invalid",          "frame.time_invalid", FT_NONE, BASE_NONE, NULL, 0x0,
546                         "The timestamp from the capture is out of the valid range", HFILL }},
547
548                 { &hf_frame_time_delta,
549                 { "Time delta from previous captured frame",    "frame.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL,
550                         0x0,
551                         "Time delta from previous captured frame", HFILL }},
552
553                 { &hf_frame_time_delta_displayed,
554                 { "Time delta from previous displayed frame",   "frame.time_delta_displayed", FT_RELATIVE_TIME, BASE_NONE, NULL,
555                         0x0,
556                         "Time delta from previous displayed frame", HFILL }},
557
558                 { &hf_frame_time_relative,
559                 { "Time since reference or first frame",        "frame.time_relative", FT_RELATIVE_TIME, BASE_NONE, NULL,
560                         0x0,
561                         "Time relative to time reference or first frame", HFILL }},
562
563                 { &hf_frame_number,
564                 { "Frame Number",               "frame.number", FT_UINT32, BASE_DEC, NULL, 0x0,
565                         "", HFILL }},
566
567                 /* Deprecated and hidden in favor of hf_frame_len / frame.len */
568                 { &hf_frame_packet_len,
569                 { "Frame length on the wire",           "frame.pkt_len", FT_UINT32, BASE_DEC, NULL, 0x0,
570                         "", HFILL }},
571
572                 { &hf_frame_len,
573                 { "Frame length on the wire",           "frame.len", FT_UINT32, BASE_DEC, NULL, 0x0,
574                         "", HFILL }},
575
576                 { &hf_frame_capture_len,
577                 { "Frame length stored into the capture file",  "frame.cap_len", FT_UINT32, BASE_DEC, NULL, 0x0,
578                         "", HFILL }},
579
580                 { &hf_frame_md5_hash,
581                 { "Frame MD5 Hash",     "frame.md5_hash", FT_STRING, 0, NULL, 0x0,
582                         NULL, HFILL }},
583
584                 { &hf_frame_p2p_dir,
585                 { "Point-to-Point Direction",   "frame.p2p_dir", FT_UINT8, BASE_DEC, VALS(p2p_dirs), 0x0,
586                         "", HFILL }},
587
588                 { &hf_link_number,
589                 { "Link Number",                "frame.link_nr", FT_UINT16, BASE_DEC, NULL, 0x0,
590                         "", HFILL }},
591
592                 { &hf_frame_file_off,
593                 { "File Offset",        "frame.file_off", FT_INT64, BASE_DEC, NULL, 0x0,
594                         "", HFILL }},
595
596                 { &hf_frame_marked,
597                 { "Frame is marked",    "frame.marked", FT_BOOLEAN, 8, NULL, 0x0,
598                         "Frame is marked in the GUI", HFILL }},
599
600                 { &hf_frame_ref_time,
601                 { "This is a Time Reference frame",     "frame.ref_time", FT_NONE, 0, NULL, 0x0,
602                         "This frame is a Time Reference frame", HFILL }},
603
604                 { &hf_frame_protocols,
605                 { "Protocols in frame", "frame.protocols", FT_STRING, 0, NULL, 0x0,
606                         "Protocols carried by this frame", HFILL }},
607
608                 { &hf_frame_color_filter_name,
609                 { "Coloring Rule Name", "frame.coloring_rule.name", FT_STRING, 0, NULL, 0x0,
610                         "The frame matched the coloring rule with this name", HFILL }},
611                 { &hf_frame_color_filter_text,
612                 { "Coloring Rule String", "frame.coloring_rule.string", FT_STRING, 0, NULL, 0x0,
613                         "The frame matched this coloring rule string", HFILL }}
614     };
615         static gint *ett[] = {
616                 &ett_frame
617         };
618         module_t *frame_module;
619
620         wtap_encap_dissector_table = register_dissector_table("wtap_encap",
621             "Wiretap encapsulation type", FT_UINT32, BASE_DEC);
622
623         proto_frame = proto_register_protocol("Frame", "Frame", "frame");
624         proto_register_field_array(proto_frame, hf, array_length(hf));
625         proto_register_subtree_array(ett, array_length(ett));
626         register_dissector("frame",dissect_frame,proto_frame);
627
628         /* You can't disable dissection of "Frame", as that would be
629            tantamount to not doing any dissection whatsoever. */
630         proto_set_cant_toggle(proto_frame);
631
632         proto_short = proto_register_protocol("Short Frame", "Short frame", "short");
633         proto_malformed = proto_register_protocol("Malformed Packet",
634             "Malformed packet", "malformed");
635         proto_unreassembled = proto_register_protocol(
636             "Unreassembled Fragmented Packet",
637             "Unreassembled fragmented packet", "unreassembled");
638
639         /* "Short Frame", "Malformed Packet", and "Unreassembled Fragmented
640            Packet" aren't really protocols, they're error indications;
641            disabling them makes no sense. */
642         proto_set_cant_toggle(proto_short);
643         proto_set_cant_toggle(proto_malformed);
644         proto_set_cant_toggle(proto_unreassembled);
645
646         /* Our preferences */
647         frame_module = prefs_register_protocol(proto_frame, NULL);
648         prefs_register_bool_preference(frame_module, "show_file_off",
649             "Show File Offset", "Show File Offset", &show_file_off);
650         prefs_register_bool_preference(frame_module, "force_docsis_encap",
651             "Treat all frames as DOCSIS frames", "Treat all frames as DOCSIS Frames", &force_docsis_encap);
652         prefs_register_bool_preference(frame_module, "generate_md5_hash",
653             "Generate an MD5 hash of each frame",
654             "Whether or not MD5 hashes should be generated for each frame, useful for finding duplicate frames.",
655             &generate_md5_hash);
656
657         frame_tap=register_tap("frame");
658 }
659
660 void
661 proto_reg_handoff_frame(void)
662 {
663         data_handle = find_dissector("data");
664         docsis_handle = find_dissector("docsis");
665 }