Ethereal-dev: Re: [Ethereal-dev] [PATCH] updated 802.11 dissector

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxx>
Date: Sat, 15 Jun 2002 13:59:06 -0700
On Fri, Jun 14, 2002 at 10:01:07AM -0400, Solomon Peachy wrote:
> > Dissectors aren't allowed to modify tvbuff data handed to them;
> > "try_decrypt_wep()" should allocate a new buffer to hold the decrypted
> > data, and return either a pointer to that buffer on success or NULL on
> > failure.  If it succeeds, a new tvbuff should be constructed with that
> > data, and added as a new "data source" with a name such as "Decrypted
> > WEP", and that tvbuff should be used when dissecting the payload.  See,
> > for example, "dissect_icqv5Client()" in "packet-icq.c" for an example of
> > the stuff to do to set up that tvbuff.
> 
> I did it in-line because I wanted the decrypted data to show up in the
> packet dump.

"Show up in the packet dump" in what sense?

If you create a new data source, it will show up in Ethereal as a
notebook page in the hex dump pane, and will show up in "tethereal -x"
output and in the output of "print to file" if "Print hex data" is
selected.

Note also that doing it in-line assumes that a dissector is allowed to
write to the tvbuff data it was handed, which is *not* the case; we do
not guarantee that doing so won't cause incorrect behavior, which is why
"tvb_get_ptr()" returns a "const guint8 *" rather than a "guint8 *" -
you are not supposed to modify the data to which that pointer points,
you're only supposed to look at it.

> > The code to handle the FCS should handle "short" frames, where the
> > snapshot length of the capture wasn't enough to get the FCS; for those
> > frames, "tvb_length()" and "tvb_reported_length()" don't return the same
> > value.  See, for example, the code in "dissect_ppp_hdlc()" in
> > "packet-ppp.c" for handing the PPP FCS.
> 
> If I understand correctly, tvb_length() returns the physical capture
> size, while tvb_reported_length() returns the length that a higher-level
> dissector tells us that we should care about.

For link-layer packets:

"tvb_reported_length()" returns the actual length of the packet on the
wire, as reported by the underlying packet capture mechanism.

"tvb_length()" returns the amount of packet data that's actually
available; this may be less than the actual length of the packet, as,
when capturing the data, you may have specified a snapshot length.

> At the 802.11 layer we have no way of knowing how long the packet is
> supposed to be, as the 802.11 header doesn't specify a packet length.

Neither do FDDI nor Token Ring nor Ethernet II; nevertheless, libpcap
*does* supply both a packet length and a captured length....

> Because there's no length, we have no way of knowing whether or not the
> FCS is really present.

All 802.11 frames have an FCS, at least as I read section 7.1.2 of
ANSI/IEEE Std 802.11, 1999 Edition, so, on the wire^H^H^H^Hair, the FCS
is always present, presumably.

Whether the underlying capture mechanism supplies the FCS to libpcap, or
whether the non-native capture file we're reading (e.g., an AiroPeek or
Wireless Sniffer capture file, in the case of 802.11) includes the FCS
as part of the packet data, is another matter.

In the case of AiroPeek and Wireless Sniffer, the answer appears to be
"it doesn't", so

	1) the 802.11 dissector common code ("dissect_ieee80211_common()")
	   needs to have an argument telling it whether the frame has an
	   FCS or not and, if that argument says it doesn't, not treat
	   the stuff at the end of the frame as an FCS

and

	2) "dissect_ieee80211_radio()" should, for now, pass to
	   "dissect_ieee80211_common()" a value of "does not contain
	   FCS", although that may change in the future - if so, we'll
	   need some mechanism by which the Wiretap code can pass an
	   indication of whether there's an FCS or not to
	   Ethereal/Tethereal.

In the case of live capture, unless *all* drivers on *all* platforms
that support 802.11 raw capture supply the FCS, there would need to be a
mechanism by which libpcap is told whether there will be an FCS at the
end of the frame or not; if we need to do that, I'd be inclined to do so
by having different DLT_ values depending on whether the FCS is present
or not, as that'd also allow tcpdump, Ethereal, etc.  to know whether
the FCS is present when reading a capture file as well as when doing a
live capture (note that, Ethereal, unlike tcpdump and Tethereal,
*always* reads a capture file, even during a live capture).

But the issue I brought up is independent of that - the problem is that
if you have, for example, a frame with a 24-byte 802.11 header, 62 bytes
of payload, and 4 bytes of FCS, *but* you capture with a snapshot length
of 68 (the tcpdump default), you will *not* get 90 bytes of data from
libpcap or from the capture file, you'll only get 68 bytes which will be
24 bytes of 802.11 header and the first 44 bytes of the payload; you
will not get the FCS, as it won't be copied to userland by the packet
capture mechanism.

In that case, "tvb_reported_length()" for the frame will be 90, and
"tvb_length()" for the frame will be 68.

> Or am I missing something?  What layer would be setting the 
> reported_length of the tvbuff when the 802.11 dissector is the top-level
> dissector in this case?

"What layer" in what sense?

The length and reported length of the first tvbuff will be set when that
tvbuff is created; that's done in "dissect_packet()" in "epan/packet.c",
which calls

	tvb_new_real_data(pd, fd->cap_len, fd->pkt_len)

The length will be set to "fd->cap_len" and the reported length will be
set to "fd->pkt_len".

That then raises the question of where "fd->cap_len" and "fd->pkt_len"
come from.  They're set in "read_packet()" in Ethereal and
"fill_in_fdata()" in Tethereal; "cap_len" is set to "phdr->caplen" and
"pkt_len" is set to "phdr->len".

However, that then raises the obvious *next* question, the answer to
which is that they're both set in Wiretap when it reads the capture
file.  For libpcap capture files, "phdr->len" and "phdr->caplen" are set
from values in the per-packet header - "phdr->len" is set to the actual
length, in bytes, of the packet on the wire or on the air, and
"phdr->caplen" is set to the number of those bytes that were actually
supplied to the program writing the capture file, which, as noted
earlier, may be smaller than the number of bytes in the packet if a
snapshot length shorter than the packet length was specified.  (Tcpdump,
as noted, defaults to a snapshot length of 68, but that can be
overridded with the "-s" flag; Ethereal and Tethereal default to a
snapshot length of 65535, but that can be overridded with the "-s" flag
or, in Ethereal, by turning the "Limit each packet to [N] bytes" option
on in the "Capture Options" dialog box, and selecting a snapshot
length.)

Those two lengths in the libpcap header come from the lengths that
libpcap supplies, which come from the underlying packet capture
mechanism, as stated above.