On Fri, Feb 22, 2002 at 06:34:56PM -0800, Guy Harris wrote:
> I decided to go with a different scheme - but, as the first segment of a
> TPKT PDU may only tell you that it's a TPKT PDU, not what's inside the
> TPKT PDU, that scheme won't work, as you won't necessarily know which
> protocol *atop* TPKT is inside the stream, so I'll look at implementing
> the other scheme.
Actually, the other scheme isn't necessary.
If you have a segment with only a TPKT header, the heuristic dissector
for the protocol in question should call the "dissect this segment as
TPKT" routine.
If you don't have TCP reassembly in general, and reassembly of the
protocol in question, enabled, that routine will dissect the TPKT header
and then call back to the "dissect a single PDU" routine for the
protocol in question - which will throw an exception, because there's no
payload for it to dissect. That's what should happen, as you can't
dissect that PDU without reassembly.
If you *do* have TCP reassembly, and reassembly of the protocol in
question, enabled, that routine will get the length of the TPKT payload
from the header and will then notice that it doesn't have the payload,
and will cause reassembly to occur without having called the "dissect a
single PDU" routine or dissected the TPKT header; that TCP segment's
data will just be shown as TCP segment data, but will be added to a
reassembly operation. When the reassembly completes, the TCP dissector
will then do the usual subdissector calls for it; if there are no
conversation-dissector or port matches (which there probably won't be,
as there weren't any when the segment was originally processed, given
that it was handed to a heuristic dissector), it'll hand that data to
the heuristic dissectors, and, in this case, there *will* be enough data
for the heuristic dissectors to recognize the packet as being one of
theirs or not.
So the current scheme involves two routines being exported to
dissectors, both declared in "packet-tpkt.h":
"is_tpkt()" - takes a tvbuff pointer as an argument, checks
whether the tvbuff begins with a TPKT header, returns the TPKT
payload length if it does and returns -1 if it doesn't;
"dissect_tpkt_encap()" - takes as arguments:
a tvbuff pointer;
a "packet_info" pointer;
a "proto_tree" pointer;
a gboolean which is the "desegmentation of this
particular protocol is enabled" variable's value;
a "dissector_handle_t" which refers to a dissector that
will dissect the payload of one TPKT packet containing a
PDU for that protocol;
and loops through the tvbuff dissecting TPKT headers and payload
until it either
runs out of data and requires further desegmentation;
dissects all the data in the tvbuff;
throws an exception.
See the Q.931 dissector for an example of how to use this:
"dissect_q931_tpkt()" is the heuristic dissector for
Q.931-over-TPKT. It checks whether the TCP data handed to it
starts with a TPKT header; if not, it returns FALSE. Then, if
it has *exactly* four bytes of TCP data, it'll immediately call
"dissect_tpkt_encap()", which will behave as I'd described
above. Otherwise, it checks whether the TCP data immediately
after that TPKT header looks like the beginning of a Q.931
message and, if so, calls "dissect_tpkt_encap()".
"dissect_q931_tpkt_pdu()" is a dissector for a single Q.931 PDU
inside TPKT. It calls "dissect_q931_pdu()", which is the
routine that does all the work of dissecting Q.931; it takes the
standard dissector arguments, plus an additional argument
indicating whether this is Q.931-over-TPKT or not.
"dissect_q931()" is a dissector for a single Q.931 PDU on top of
LAPB. It also calls "dissect_q931_pdu()", with the additional
argument being FALSE.
"dissect_q931_pdu()" is the routine to dissect a Q.931 PDU. If
the additional Boolean argument is TRUE, and it sees a
variable-length information element that's a User-User
information element with a protocol discriminator of Q.931, it
dissects the header of the IE and, if it has any data and the
Q.931 dissector found a handle for an H.225 Call Setup
dissector, hands it to that dissector, otherwise it just shows
it as undissected "User information".
The H.225 Call Setup dissector should register itself with a call to
"register_dissector()" with a dissector name of "h225_cs".