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