Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-dev: Re: [Wireshark-dev] Sub_dissectors assertion failed

From: Guy Harris <guy@xxxxxxxxxxxx>
Date: Fri, 21 May 2010 14:18:44 -0700
On May 21, 2010, at 12:49 PM, Scott wrote:

> I killed the original error of
> ERROR:packet.c:709:dissector_add: assertion failed: (sub_dissectors)
> by calling register_dissector_table() in proto_register_..().  Apparently I didn't know I needed to do that, but it makes sense.

Yes.  As indicated:

	1) you can't register in a dissector table until the dissector table is registered;

	2) the *only* ordering guarantee we offer is that all register routines are run before any register-handoff routines are run;

so, to make sure that all the dissector tables are registered before any registrations are attempted in dissector tables, you must register dissector tables in your register routine and register dissectors *in* dissector tables in the register-handoff routines (dissector tables are used by dissectors to hand off the remaining packet data to the next protocol, hence the "handoff" in "register-handoff").

> I mean *any protocol that runs atop IP* can follow it.

Then you want to do what I suggested to find the right dissector for the following protocol - just get the "ip.proto" dissector table and use that.

> I am going to work on all protocols registered with IP to follow it as soon as I get *another* custom dissector/protocol that I am working on, which can follow it, to work.  Let's call the custom protocol *custom* and the IP rider *it* to simplify things.
> 
> I have the custom protocol doing dissector_add("[field switch on *it*]", [macro expansion that matches a field value], *custom*_handle) in its handoff routine.  However, for some reason it is apparently not being called upon to dissect because it is not showing up as a header in the packet window.

So what protocols does your custom protocol run on top of?  It needs to register with the appropriate dissector table or tables for those protocols, using the appropriate value (Ethernet type, IP protocol type, etc.).

> As a "by the way," you mentioned in your reply:
> If you mean, for example, "any protocol that runs atop IP", then you should grab hold of the "ip.proto" dissector table:
> 
>        dissector_table_t ip_proto_dissector_table;
>                ...
>        ip_proto_dissector_table = find_dissector_table("ip.proto");
> 
> and then use that to hand off the payload to the next dissector with that dissector table, the protocol number, and dissector_try_port().
> How do I "hand off the payload to the next dissector with that dissector table, the protocol number, and dissector_try_port()?"  Is that through a function call?

Yes.

The name of the function you call is "dissector_try_port".

> And what does dissector_try_port() do?  All I could tell is that it returns a gboolean.

It takes, as arguments:

	1) a handle for a dissector table that uses integral values as keys (it should really be dissector_try_uint(); the "port" is historical);

	2) an integral value to use to select a dissector from that dissector table;

	3) a tvbuff_t * that refers to a tvbuff with the data to be dissected by the selected dissector;

	4) a packet_info *, which should be the one the dissector calling dissector_try_port() was handed;

	5) a proto_tree *, which should be the one the dissector calling dissector_try_port() was handed.

If it finds a dissector in the dissector table that was registered with the integral value in question, it calls it, handing it the tvbuff_t *, the packet_info *, and the proto_tree *, and returns TRUE.  If not, it returns FALSE; you then need to decide how to dissect the data (for example, just show it as raw data).

For example, the Ethernet dissector calls dissector_try_port(), handing it the Ethernet-type dissector table, and the Ethernet type value from the packet.

> More questions I haven't been able to find answers to:
> *The proto_handoff_..(void) routine's main job is to register the dissector with other dissectors so it gets called at the right moment, correct?

Yes.

> *What is the difference between create_dissector_handle() and new_create_dissector_handle()?

There are two types of dissectors:

	1) dissectors for protocol fields such as Ethernet types where the value used when you select a dissector (integral value for dissector_try_port()) is uniquely assigned to a protocol, so that you can pretty much guarantee that the selected dissector is the right one;

	2) dissectors for protocol fields such as UDP or TCP ports where the value is assigned to the protocol but could be used by other protocols, so you *can't* guarantee that the selected dissector is the right one.

In addition, in some cases the calling dissector needs to know how much data from the tvbuff was considered part of the data for the called dissector's protocol, i.e. where it doesn't always get the rest of the packet.

"New-style" dissectors are for case 2) and for the other case mentioned.  For case 2), they do some heuristic checks to see if the packet looks appropriate for their protocol and, if not, they return 0 without having done any dissection, otherwise they return the amount of data dissected.  For the other case, they return the amount of data dissected.

(This has a problem if there's no packet data left to dissect, i.e. the tvbuff handed to them is zero-length; you can't distinguish between "this isn't one of my packets" and "this is one of my packets, and I dissected all 0 bytes of it".  Yes, there are cases where this is a problem.)