Enable Lua tcp tap userdata.
[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 static int hf_frame_time_reference = -1;
55 int hf_frame_number = -1;
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_link_number = -1;
63 static int hf_frame_protocols = -1;
64 static int hf_frame_color_filter_name = -1;
65 static int hf_frame_color_filter_text = -1;
66
67 static int proto_short = -1;
68 int proto_malformed = -1;
69 static int proto_unreassembled = -1;
70
71 static gint ett_frame = -1;
72
73 static int frame_tap = -1;
74
75 static dissector_handle_t data_handle;
76 static dissector_handle_t docsis_handle;
77
78 /* Preferences */
79 static gboolean show_file_off = FALSE;
80 static gboolean force_docsis_encap = FALSE;
81 static gboolean generate_md5_hash = FALSE;
82
83 static const value_string p2p_dirs[] = {
84         { P2P_DIR_UNKNOWN, "Unknown" },
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                         break;
149
150                 case WTAP_ENCAP_LAPB:
151                 case WTAP_ENCAP_FRELAY_WITH_PHDR:
152                         pinfo->p2p_dir =
153                             (pinfo->pseudo_header->x25.flags & FROM_DCE) ?
154                             P2P_DIR_RECV : P2P_DIR_SENT;
155                         break;
156
157                 case WTAP_ENCAP_ISDN:
158                         pinfo->p2p_dir = pinfo->pseudo_header->isdn.uton ?
159                             P2P_DIR_SENT : P2P_DIR_RECV;
160                         break;
161
162                 case WTAP_ENCAP_LINUX_LAPD:
163                         pinfo->p2p_dir = (pinfo->pseudo_header->lapd.pkttype == 3 ||
164                                 pinfo->pseudo_header->lapd.pkttype == 4) ?
165                                 P2P_DIR_SENT : P2P_DIR_RECV;
166                         break;
167
168                 case WTAP_ENCAP_MTP2_WITH_PHDR:
169                         pinfo->p2p_dir = pinfo->pseudo_header->mtp2.sent ?
170                             P2P_DIR_SENT : P2P_DIR_RECV;
171                         pinfo->link_number  = pinfo->pseudo_header->mtp2.link_number;
172                         pinfo->annex_a_used = pinfo->pseudo_header->mtp2.annex_a_used;
173                         break;
174
175                 case WTAP_ENCAP_GSM_UM:
176                         pinfo->p2p_dir = pinfo->pseudo_header->gsm_um.uplink ?
177                             P2P_DIR_SENT : P2P_DIR_RECV;
178                         break;
179
180                 }
181         }
182
183         /* Put in frame header information. */
184         if (tree) {
185           cap_len = tvb_length(tvb);
186           frame_len = tvb_reported_length(tvb);
187
188           ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, -1,
189             "Frame %u (%u bytes on wire, %u bytes captured)", pinfo->fd->num, frame_len, cap_len);
190
191           fh_tree = proto_item_add_subtree(ti, ett_frame);
192         }
193
194         /* if FRAME is not referenced from any filters we dont need to worry about
195            generating any tree items.  We must do this after we created the actual
196            protocol above so that proto hier stat still works though.
197         */
198         if(!proto_field_is_referenced(tree, proto_frame)){
199                 tree=NULL;
200                 fh_tree = NULL;
201         }
202
203
204         if (fh_tree) {
205           ts = pinfo->fd->abs_ts;
206
207           proto_tree_add_time(fh_tree, hf_frame_arrival_time, tvb,
208                 0, 0, &ts);
209           if(ts.nsecs < 0 || ts.nsecs >= 1000000000) {
210             item = proto_tree_add_none_format(fh_tree, hf_frame_time_invalid, tvb,
211                   0, 0, "Arrival Time: Fractional second %09ld is invalid, the valid range is 0-1000000000", (long) ts.nsecs);
212             PROTO_ITEM_SET_GENERATED(item);
213             expert_add_info_format(pinfo, item, PI_MALFORMED, PI_WARN, "Arrival Time: Fractional second out of range (0-1000000000)");
214           }
215
216           ts = pinfo->fd->del_cap_ts;
217
218           item = proto_tree_add_time(fh_tree, hf_frame_time_delta, tvb,
219                 0, 0, &ts);
220           PROTO_ITEM_SET_GENERATED(item);
221
222           ts = pinfo->fd->del_dis_ts;
223
224           item = proto_tree_add_time(fh_tree, hf_frame_time_delta_displayed, tvb,
225                 0, 0, &ts);
226           PROTO_ITEM_SET_GENERATED(item);
227
228           ts = pinfo->fd->rel_ts;
229
230           item = proto_tree_add_time(fh_tree, hf_frame_time_relative, tvb,
231                 0, 0, &ts);
232           PROTO_ITEM_SET_GENERATED(item);
233
234           if(pinfo->fd->flags.ref_time){
235                 ti = proto_tree_add_item(fh_tree, hf_frame_time_reference, tvb, 0, 0, FALSE);
236                 PROTO_ITEM_SET_GENERATED(ti);
237           }
238
239           proto_tree_add_uint(fh_tree, hf_frame_number, tvb,
240                 0, 0, pinfo->fd->num);
241
242           proto_tree_add_uint_format(fh_tree, hf_frame_len, tvb,
243                 0, 0, frame_len, "Frame Length: %d byte%s", frame_len,
244                 plurality(frame_len, "", "s"));
245
246           proto_tree_add_uint_format(fh_tree, hf_frame_capture_len, tvb,
247                 0, 0, cap_len, "Capture Length: %d byte%s", cap_len,
248                 plurality(cap_len, "", "s"));
249
250           if (generate_md5_hash) {
251                   const guint8 *cp;
252                   md5_state_t md_ctx;
253                   md5_byte_t digest[16];
254                   gchar *digest_string;
255
256                   cp = tvb_get_ptr(tvb, 0, cap_len);
257
258                   md5_init(&md_ctx);
259                   md5_append(&md_ctx, cp, cap_len);
260                   md5_finish(&md_ctx, digest);
261
262                   digest_string = bytestring_to_str(digest, 16, '\0');
263                   ti = proto_tree_add_string(fh_tree, hf_frame_md5_hash, tvb, 0, 0, digest_string);
264                   PROTO_ITEM_SET_GENERATED(ti);
265           }
266
267           ti = proto_tree_add_boolean(fh_tree, hf_frame_marked, tvb, 0, 0,pinfo->fd->flags.marked);
268           PROTO_ITEM_SET_GENERATED(ti);
269
270           /* we are going to be using proto_item_append_string() on
271            * hf_frame_protocols, and we must therefore disable the
272            * TRY_TO_FAKE_THIS_ITEM() optimisation for the tree by
273            * setting it as visible.
274            *
275            * See proto.h for details.
276            */
277           proto_tree_set_visible(fh_tree, TRUE);
278
279           ti = proto_tree_add_string(fh_tree, hf_frame_protocols, tvb,
280                 0, 0, "");
281           PROTO_ITEM_SET_GENERATED(ti);
282           pinfo->layer_names = g_string_new("");
283
284           /* Check for existences of P2P pseudo header */
285           if (pinfo->p2p_dir != P2P_DIR_UNKNOWN) {
286                   proto_tree_add_int(fh_tree, hf_frame_p2p_dir, tvb,
287                                   0, 0, pinfo->p2p_dir);
288           }
289
290           /* Check for existences of MTP2 link number */
291           if ((pinfo->pseudo_header != NULL ) && (pinfo->fd->lnk_t == WTAP_ENCAP_MTP2_WITH_PHDR)) {
292                   proto_tree_add_uint(fh_tree, hf_link_number, tvb,
293                                   0, 0, pinfo->link_number);
294           }
295
296           if (show_file_off) {
297                   proto_tree_add_int64_format(fh_tree, hf_frame_file_off, tvb,
298                                   0, 0, pinfo->fd->file_off,
299                                   "File Offset: %" G_GINT64_MODIFIER "d (0x%" G_GINT64_MODIFIER "x)",
300                                   pinfo->fd->file_off, pinfo->fd->file_off);
301           }
302
303           if(pinfo->fd->color_filter != NULL) {
304               color_filter_t *color_filter = pinfo->fd->color_filter;
305               item = proto_tree_add_string(fh_tree, hf_frame_color_filter_name, tvb,
306                     0, 0, color_filter->filter_name);
307               PROTO_ITEM_SET_GENERATED(item);
308               item = proto_tree_add_string(fh_tree, hf_frame_color_filter_text, tvb,
309                     0, 0, color_filter->filter_text);
310               PROTO_ITEM_SET_GENERATED(item);
311           }
312         } else {
313           if(pinfo->fd->abs_ts.nsecs < 0 || pinfo->fd->abs_ts.nsecs >= 1000000000) {
314                 expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_WARN, "Arrival Time: Fractional second out of range (0-1000000000)");
315           }
316         }
317
318     /* Portable Exception Handling to trap Wireshark specific exceptions like BoundsError exceptions */
319         TRY {
320 #ifdef _MSC_VER
321     /* Win32: Visual-C Structured Exception Handling (SEH) to trap hardware exceptions like memory access violations */
322     /* (a running debugger will be called before the except part below) */
323     __try {
324 #endif
325         if ((force_docsis_encap) && (docsis_handle)) {
326             call_dissector(docsis_handle, tvb, pinfo, parent_tree);
327         } else {
328             if (!dissector_try_port(wtap_encap_dissector_table, pinfo->fd->lnk_t,
329                 tvb, pinfo, parent_tree)) {
330
331                         if (check_col(pinfo->cinfo, COL_PROTOCOL))
332                                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UNKNOWN");
333                         if (check_col(pinfo->cinfo, COL_INFO))
334                                 col_add_fstr(pinfo->cinfo, COL_INFO, "WTAP_ENCAP = %u",
335                                     pinfo->fd->lnk_t);
336                         call_dissector(data_handle,tvb, pinfo, parent_tree);
337                 }
338         }
339 #ifdef _MSC_VER
340     } __except(TRUE /* handle all exceptions */) {
341         switch(GetExceptionCode()) {
342         case(STATUS_ACCESS_VIOLATION):
343                     show_exception(tvb, pinfo, parent_tree, DissectorError,
344                 "STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
345             break;
346         case(STATUS_INTEGER_DIVIDE_BY_ZERO):
347                     show_exception(tvb, pinfo, parent_tree, DissectorError,
348                 "STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
349             break;
350         case(STATUS_STACK_OVERFLOW):
351                     show_exception(tvb, pinfo, parent_tree, DissectorError,
352                 "STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
353             /* XXX - this will have probably corrupted the stack, which makes problems later in the exception code */
354             break;
355         /* XXX - add other hardware exception codes as required */
356         default:
357                     show_exception(tvb, pinfo, parent_tree, DissectorError,
358                 g_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
359         }
360     }
361 #endif
362         }
363         CATCH(OutOfMemoryError) {
364                 RETHROW;
365         }
366         CATCH_ALL {
367                 show_exception(tvb, pinfo, parent_tree, EXCEPT_CODE, GET_MESSAGE);
368         }
369         ENDTRY;
370
371         if (tree && pinfo->layer_names) {
372                 proto_item_append_string(ti, pinfo->layer_names->str);
373                 g_string_free(pinfo->layer_names, TRUE);
374                 pinfo->layer_names = NULL;
375         }
376
377         /*  Call postdissectors if we have any (while trying to avoid another
378          *  TRY/CATCH)
379          */
380         if (have_postdissector()) {
381             TRY {
382 #ifdef _MSC_VER
383             /* Win32: Visual-C Structured Exception Handling (SEH) to trap hardware exceptions like memory access violations */
384             /* (a running debugger will be called before the except part below) */
385             __try {
386 #endif
387                 call_all_postdissectors(tvb, pinfo, parent_tree);
388 #ifdef _MSC_VER
389             } __except(TRUE /* handle all exceptions */) {
390                 switch(GetExceptionCode()) {
391                 case(STATUS_ACCESS_VIOLATION):
392                             show_exception(tvb, pinfo, parent_tree, DissectorError,
393                         "STATUS_ACCESS_VIOLATION: dissector accessed an invalid memory address");
394                     break;
395                 case(STATUS_INTEGER_DIVIDE_BY_ZERO):
396                             show_exception(tvb, pinfo, parent_tree, DissectorError,
397                         "STATUS_INTEGER_DIVIDE_BY_ZERO: dissector tried an integer division by zero");
398                     break;
399                 case(STATUS_STACK_OVERFLOW):
400                             show_exception(tvb, pinfo, parent_tree, DissectorError,
401                         "STATUS_STACK_OVERFLOW: dissector overflowed the stack (e.g. endless loop)");
402                     /* XXX - this will have probably corrupted the stack, which makes problems later in the exception code */
403                     break;
404                 /* XXX - add other hardware exception codes as required */
405                 default:
406                             show_exception(tvb, pinfo, parent_tree, DissectorError,
407                         g_strdup_printf("dissector caused an unknown exception: 0x%x", GetExceptionCode()));
408                 }
409             }
410 #endif
411             }
412             CATCH(OutOfMemoryError) {
413                     RETHROW;
414             }
415             CATCH_ALL {
416                     show_exception(tvb, pinfo, parent_tree, EXCEPT_CODE, GET_MESSAGE);
417             }
418             ENDTRY;
419         }
420
421         tap_queue_packet(frame_tap, pinfo, NULL);
422
423
424         if (frame_end_routines) {
425                 g_slist_foreach(frame_end_routines, &call_frame_end_routine, NULL);
426                 g_slist_free(frame_end_routines);
427                 frame_end_routines = NULL;
428         }
429 }
430
431 void
432 show_exception(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
433     unsigned long exception, const char *exception_message)
434 {
435         static const char dissector_error_nomsg[] =
436             "Dissector writer didn't bother saying what the error was";
437         proto_item *item;
438
439
440         switch (exception) {
441
442         case ScsiBoundsError:
443                 if (check_col(pinfo->cinfo, COL_INFO))
444                         col_append_str(pinfo->cinfo, COL_INFO, "[SCSI transfer limited due to allocation_length too small]");
445                 /*item =*/ proto_tree_add_protocol_format(tree, proto_short, tvb, 0, 0,
446                                 "SCSI transfer limited due to allocation_length too small: %s truncated]", pinfo->current_proto);
447                 /* Don't record ScsiBoundsError exceptions as expert events - they merely
448                  * reflect a normal SCSI condition.
449                  * (any case where it's caused by something else is a bug). */
450                 /* expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Packet size limited");*/
451                 break;
452
453         case BoundsError:
454                 if (check_col(pinfo->cinfo, COL_INFO))
455                         col_append_str(pinfo->cinfo, COL_INFO, "[Packet size limited during capture]");
456                 /*item =*/ proto_tree_add_protocol_format(tree, proto_short, tvb, 0, 0,
457                                 "[Packet size limited during capture: %s truncated]", pinfo->current_proto);
458                 /* Don't record BoundsError exceptions as expert events - they merely
459                  * reflect a capture done with a snapshot length too short to capture
460                  * all of the packet
461                  * (any case where it's caused by something else is a bug). */
462                 /* expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Packet size limited");*/
463                 break;
464
465         case ReportedBoundsError:
466                 show_reported_bounds_error(tvb, pinfo, tree);
467                 break;
468
469         case DissectorError:
470                 if (check_col(pinfo->cinfo, COL_INFO))
471                         col_append_fstr(pinfo->cinfo, COL_INFO,
472                             "[Dissector bug, protocol %s: %s]",
473                             pinfo->current_proto,
474                             exception_message == NULL ?
475                                 dissector_error_nomsg : exception_message);
476                 item = proto_tree_add_protocol_format(tree, proto_malformed, tvb, 0, 0,
477                     "[Dissector bug, protocol %s: %s]",
478                     pinfo->current_proto,
479                     exception_message == NULL ?
480                         dissector_error_nomsg : exception_message);
481                 g_warning("Dissector bug, protocol %s, in packet %u: %s",
482                     pinfo->current_proto, pinfo->fd->num,
483                     exception_message == NULL ?
484                         dissector_error_nomsg : exception_message);
485                 expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR,
486                     "%s",
487                     exception_message == NULL ?
488                         dissector_error_nomsg : exception_message);
489                 break;
490
491         default:
492                 /* XXX - we want to know, if an unknown exception passed until here, don't we? */
493                 g_assert_not_reached();
494         }
495 }
496
497 void
498 show_reported_bounds_error(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
499 {
500         proto_item *item;
501
502         if (pinfo->fragmented) {
503                 /*
504                  * We were dissecting an unreassembled fragmented
505                  * packet when the exception was thrown, so the
506                  * problem isn't that the dissector expected
507                  * something but it wasn't in the packet, the
508                  * problem is that the dissector expected something
509                  * but it wasn't in the fragment we dissected.
510                  */
511                 if (check_col(pinfo->cinfo, COL_INFO))
512                         col_append_fstr(pinfo->cinfo, COL_INFO,
513                             "[Unreassembled Packet%s] ",
514                             pinfo->noreassembly_reason);
515                 item = proto_tree_add_protocol_format(tree, proto_unreassembled,
516                     tvb, 0, 0, "[Unreassembled Packet%s: %s]",
517                     pinfo->noreassembly_reason, pinfo->current_proto);
518                 expert_add_info_format(pinfo, item, PI_REASSEMBLE, PI_WARN, "Unreassembled Packet (Exception occurred)");
519         } else {
520                 if (check_col(pinfo->cinfo, COL_INFO))
521                         col_append_str(pinfo->cinfo, COL_INFO,
522                             "[Malformed Packet]");
523                 item = proto_tree_add_protocol_format(tree, proto_malformed,
524                     tvb, 0, 0, "[Malformed Packet: %s]", pinfo->current_proto);
525                 expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Malformed Packet (Exception occurred)");
526         }
527 }
528
529 void
530 proto_register_frame(void)
531 {
532         static hf_register_info hf[] = {
533                 { &hf_frame_arrival_time,
534                 { "Arrival Time",               "frame.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
535                         "Absolute time when this frame was captured", HFILL }},
536
537                 { &hf_frame_time_invalid,
538                 { "Arrival Timestamp invalid",          "frame.time_invalid", FT_NONE, BASE_NONE, NULL, 0x0,
539                         "The timestamp from the capture is out of the valid range", HFILL }},
540
541                 { &hf_frame_time_delta,
542                 { "Time delta from previous captured frame",    "frame.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL,
543                         0x0,
544                         NULL, HFILL }},
545
546                 { &hf_frame_time_delta_displayed,
547                 { "Time delta from previous displayed frame",   "frame.time_delta_displayed", FT_RELATIVE_TIME, BASE_NONE, NULL,
548                         0x0,
549                         NULL, HFILL }},
550
551                 { &hf_frame_time_relative,
552                 { "Time since reference or first frame",        "frame.time_relative", FT_RELATIVE_TIME, BASE_NONE, NULL,
553                         0x0,
554                         "Time relative to time reference or first frame", HFILL }},
555
556                 { &hf_frame_time_reference,
557                 { "This is a Time Reference frame",     "frame.ref_time", FT_NONE, 0, NULL, 0x0,
558                         "This frame is a Time Reference frame", HFILL }},
559
560                 { &hf_frame_number,
561                 { "Frame Number",               "frame.number", FT_UINT32, BASE_DEC, NULL, 0x0,
562                         NULL, HFILL }},
563
564                 { &hf_frame_len,
565                 { "Frame length on the wire",           "frame.len", FT_UINT32, BASE_DEC, NULL, 0x0,
566                         NULL, HFILL }},
567
568                 { &hf_frame_capture_len,
569                 { "Frame length stored into the capture file",  "frame.cap_len", FT_UINT32, BASE_DEC, NULL, 0x0,
570                         NULL, HFILL }},
571
572                 { &hf_frame_md5_hash,
573                 { "Frame MD5 Hash",     "frame.md5_hash", FT_STRING, 0, NULL, 0x0,
574                         NULL, HFILL }},
575
576                 { &hf_frame_p2p_dir,
577                 { "Point-to-Point Direction",   "frame.p2p_dir", FT_INT8, BASE_DEC, VALS(p2p_dirs), 0x0,
578                         NULL, HFILL }},
579
580                 { &hf_link_number,
581                 { "Link Number",                "frame.link_nr", FT_UINT16, BASE_DEC, NULL, 0x0,
582                         NULL, HFILL }},
583
584                 { &hf_frame_file_off,
585                 { "File Offset",        "frame.file_off", FT_INT64, BASE_DEC, NULL, 0x0,
586                         NULL, HFILL }},
587
588                 { &hf_frame_marked,
589                 { "Frame is marked",    "frame.marked", FT_BOOLEAN, 8, NULL, 0x0,
590                         "Frame is marked in the GUI", HFILL }},
591
592                 { &hf_frame_protocols,
593                 { "Protocols in frame", "frame.protocols", FT_STRING, 0, NULL, 0x0,
594                         "Protocols carried by this frame", HFILL }},
595
596                 { &hf_frame_color_filter_name,
597                 { "Coloring Rule Name", "frame.coloring_rule.name", FT_STRING, 0, NULL, 0x0,
598                         "The frame matched the coloring rule with this name", HFILL }},
599
600                 { &hf_frame_color_filter_text,
601                 { "Coloring Rule String", "frame.coloring_rule.string", FT_STRING, 0, NULL, 0x0,
602                         "The frame matched this coloring rule string", HFILL }}
603         };
604         static gint *ett[] = {
605                 &ett_frame
606         };
607         module_t *frame_module;
608
609         wtap_encap_dissector_table = register_dissector_table("wtap_encap",
610             "Wiretap encapsulation type", FT_UINT32, BASE_DEC);
611
612         proto_frame = proto_register_protocol("Frame", "Frame", "frame");
613         proto_register_field_array(proto_frame, hf, array_length(hf));
614         proto_register_subtree_array(ett, array_length(ett));
615         register_dissector("frame",dissect_frame,proto_frame);
616
617         /* You can't disable dissection of "Frame", as that would be
618            tantamount to not doing any dissection whatsoever. */
619         proto_set_cant_toggle(proto_frame);
620
621         proto_short = proto_register_protocol("Short Frame", "Short frame", "short");
622         proto_malformed = proto_register_protocol("Malformed Packet",
623             "Malformed packet", "malformed");
624         proto_unreassembled = proto_register_protocol(
625             "Unreassembled Fragmented Packet",
626             "Unreassembled fragmented packet", "unreassembled");
627
628         /* "Short Frame", "Malformed Packet", and "Unreassembled Fragmented
629            Packet" aren't really protocols, they're error indications;
630            disabling them makes no sense. */
631         proto_set_cant_toggle(proto_short);
632         proto_set_cant_toggle(proto_malformed);
633         proto_set_cant_toggle(proto_unreassembled);
634
635         /* Our preferences */
636         frame_module = prefs_register_protocol(proto_frame, NULL);
637         prefs_register_bool_preference(frame_module, "show_file_off",
638             "Show File Offset", "Show offset of frame in capture file", &show_file_off);
639         prefs_register_bool_preference(frame_module, "force_docsis_encap",
640             "Treat all frames as DOCSIS frames", "Treat all frames as DOCSIS Frames", &force_docsis_encap);
641         prefs_register_bool_preference(frame_module, "generate_md5_hash",
642             "Generate an MD5 hash of each frame",
643             "Whether or not MD5 hashes should be generated for each frame, useful for finding duplicate frames.",
644             &generate_md5_hash);
645
646         frame_tap=register_tap("frame");
647 }
648
649 void
650 proto_reg_handoff_frame(void)
651 {
652         data_handle = find_dissector("data");
653         docsis_handle = find_dissector("docsis");
654 }