*
* $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <glib.h>
#include <epan/packet.h>
#include <epan/prefs.h>
-#include "etypes.h"
+#include <epan/etypes.h>
#include <epan/addr_resolv.h>
#include "packet-eth.h"
#include "packet-ieee8023.h"
#include <epan/crc32.h>
#include <epan/tap.h>
+/* Assume all packets have an FCS */
+static gboolean eth_assume_fcs = FALSE;
/* Interpret packets as FW1 monitor file packets if they look as if they are */
static gboolean eth_interpret_as_fw1_monitor = FALSE;
+/* Preference settings defining conditions for which the CCSDS dissector is called */
+static gboolean ccsds_heuristic_length = FALSE;
+static gboolean ccsds_heuristic_version = FALSE;
+static gboolean ccsds_heuristic_header = FALSE;
+static gboolean ccsds_heuristic_bit = FALSE;
/* protocols and header fields */
static int proto_eth = -1;
static int hf_eth_len = -1;
static int hf_eth_type = -1;
static int hf_eth_addr = -1;
+static int hf_eth_ig = -1;
+static int hf_eth_lg = -1;
static int hf_eth_trailer = -1;
static gint ett_ieee8023 = -1;
static gint ett_ether2 = -1;
+static gint ett_addr = -1;
static dissector_handle_t fw1_handle;
static heur_dissector_list_t heur_subdissector_list;
+static heur_dissector_list_t eth_trailer_subdissector_list;
static int eth_tap = -1;
#define ETH_HEADER_SIZE 14
+static const true_false_string ig_tfs = {
+ "Group address (multicast/broadcast)",
+ "Individual address (unicast)"
+};
+static const true_false_string lg_tfs = {
+ "Locally administered address (this is NOT the factory default)",
+ "Globally unique address (factory default)"
+};
+
/* These are the Netware-ish names for the different Ethernet frame types.
EthernetII: The ethernet with a Type field instead of a length field
Ethernet802.2: An 802.3 header followed by an 802.2 header
}
}
+static gboolean check_is_802_2(tvbuff_t *tvb, int fcs_len);
+
static void
dissect_eth_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
int fcs_len)
{
proto_item *ti;
- eth_hdr *volatile ehdr;
- volatile gboolean is_802_2;
- proto_tree *volatile fh_tree = NULL;
- const char *src_addr, *dst_addr;
+ eth_hdr *ehdr;
+ gboolean is_802_2;
+ proto_tree *fh_tree = NULL;
+ const guint8 *src_addr, *dst_addr;
static eth_hdr ehdrs[4];
static int ehdr_num=0;
- proto_tree *volatile tree;
+ proto_tree *tree;
+ proto_item *addr_item;
+ proto_tree *addr_tree=NULL;
ehdr_num++;
if(ehdr_num>=4){
tree=parent_tree;
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "Ethernet");
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Ethernet");
src_addr=tvb_get_ptr(tvb, 6, 6);
SET_ADDRESS(&pinfo->dl_src, AT_ETHER, 6, src_addr);
ehdr->type = tvb_get_ntohs(tvb, 12);
+ tap_queue_packet(eth_tap, pinfo, ehdr);
+
/*
* In case the packet is a non-Ethernet packet inside
* Ethernet framing, allow heuristic dissectors to take
* Ethernet packet.
*/
if (dissector_try_heuristic(heur_subdissector_list, tvb, pinfo, parent_tree))
- goto end_of_eth;
+ return;
if (ehdr->type <= IEEE_802_3_MAX_LEN) {
/* Oh, yuck. Cisco ISL frames require special interpretation of the
tvb_get_guint8(tvb, 3) == 0x00 &&
tvb_get_guint8(tvb, 4) == 0x00 ) {
dissect_isl(tvb, pinfo, parent_tree, fcs_len);
- goto end_of_eth;
+ return;
}
}
* an ethernet type of ETHERTYPE_UNK.
*/
if (ehdr->type <= IEEE_802_3_MAX_LEN && ehdr->type != ETHERTYPE_UNK) {
- /* Is there an 802.2 layer? I can tell by looking at the first 2
- bytes after the 802.3 header. If they are 0xffff, then what
- follows the 802.3 header is an IPX payload, meaning no 802.2.
- (IPX/SPX is they only thing that can be contained inside a
- straight 802.3 packet). A non-0xffff value means that there's an
- 802.2 layer inside the 802.3 layer */
- is_802_2 = TRUE;
- TRY {
- if (tvb_get_ntohs(tvb, 14) == 0xffff) {
- is_802_2 = FALSE;
- }
- }
- CATCH2(BoundsError, ReportedBoundsError) {
- ; /* do nothing */
- }
- ENDTRY;
+ is_802_2 = check_is_802_2(tvb, fcs_len);
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_add_fstr(pinfo->cinfo, COL_INFO, "IEEE 802.3 Ethernet %s",
+ col_add_fstr(pinfo->cinfo, COL_INFO, "IEEE 802.3 Ethernet %s",
(is_802_2 ? "" : "Raw "));
- }
if (tree) {
ti = proto_tree_add_protocol_format(tree, proto_eth, tvb, 0, ETH_HEADER_SIZE,
"IEEE 802.3 Ethernet %s", (is_802_2 ? "" : "Raw "));
fh_tree=NULL;
}
- proto_tree_add_ether(fh_tree, hf_eth_dst, tvb, 0, 6, dst_addr);
- proto_tree_add_ether(fh_tree, hf_eth_src, tvb, 6, 6, src_addr);
+ addr_item=proto_tree_add_ether(fh_tree, hf_eth_dst, tvb, 0, 6, dst_addr);
+ if(addr_item){
+ addr_tree = proto_item_add_subtree(addr_item, ett_addr);
+ }
+ proto_tree_add_ether(addr_tree, hf_eth_addr, tvb, 0, 6, dst_addr);
+ proto_tree_add_item(addr_tree, hf_eth_ig, tvb, 0, 3, FALSE);
+ proto_tree_add_item(addr_tree, hf_eth_lg, tvb, 0, 3, FALSE);
-/* add items for eth.addr filter */
- proto_tree_add_ether_hidden(fh_tree, hf_eth_addr, tvb, 0, 6, dst_addr);
- proto_tree_add_ether_hidden(fh_tree, hf_eth_addr, tvb, 6, 6, src_addr);
+ addr_item=proto_tree_add_ether(fh_tree, hf_eth_src, tvb, 6, 6, src_addr);
+ if(addr_item){
+ addr_tree = proto_item_add_subtree(addr_item, ett_addr);
+ }
+ proto_tree_add_ether(addr_tree, hf_eth_addr, tvb, 6, 6, src_addr);
+ proto_tree_add_item(addr_tree, hf_eth_ig, tvb, 6, 3, FALSE);
+ proto_tree_add_item(addr_tree, hf_eth_lg, tvb, 6, 3, FALSE);
dissect_802_3(ehdr->type, is_802_2, tvb, ETH_HEADER_SIZE, pinfo, parent_tree, fh_tree,
hf_eth_len, hf_eth_trailer, fcs_len);
if ((dst_addr[0] == 'i') || (dst_addr[0] == 'I') ||
(dst_addr[0] == 'o') || (dst_addr[0] == 'O')) {
call_dissector(fw1_handle, tvb, pinfo, parent_tree);
- goto end_of_eth;
+ return;
}
}
- if (check_col(pinfo->cinfo, COL_INFO))
- col_set_str(pinfo->cinfo, COL_INFO, "Ethernet II");
+ col_set_str(pinfo->cinfo, COL_INFO, "Ethernet II");
if (parent_tree) {
- ti = proto_tree_add_protocol_format(parent_tree, proto_eth, tvb, 0, ETH_HEADER_SIZE,
+ if (PTREE_DATA(parent_tree)->visible) {
+ ti = proto_tree_add_protocol_format(parent_tree, proto_eth, tvb, 0, ETH_HEADER_SIZE,
"Ethernet II, Src: %s (%s), Dst: %s (%s)",
get_ether_name(src_addr), ether_to_str(src_addr), get_ether_name(dst_addr), ether_to_str(dst_addr));
-
+ }
+ else {
+ ti = proto_tree_add_item(parent_tree, proto_eth, tvb, 0, ETH_HEADER_SIZE, FALSE);
+ }
fh_tree = proto_item_add_subtree(ti, ett_ether2);
}
- proto_tree_add_ether(fh_tree, hf_eth_dst, tvb, 0, 6, dst_addr);
- proto_tree_add_ether(fh_tree, hf_eth_src, tvb, 6, 6, src_addr);
-/* add items for eth.addr filter */
- proto_tree_add_ether_hidden(fh_tree, hf_eth_addr, tvb, 0, 6, dst_addr);
- proto_tree_add_ether_hidden(fh_tree, hf_eth_addr, tvb, 6, 6, src_addr);
+ addr_item=proto_tree_add_ether(fh_tree, hf_eth_dst, tvb, 0, 6, dst_addr);
+ if(addr_item){
+ addr_tree = proto_item_add_subtree(addr_item, ett_addr);
+ }
+ proto_tree_add_ether(addr_tree, hf_eth_addr, tvb, 0, 6, dst_addr);
+ proto_tree_add_item(addr_tree, hf_eth_ig, tvb, 0, 3, FALSE);
+ proto_tree_add_item(addr_tree, hf_eth_lg, tvb, 0, 3, FALSE);
+
+ addr_item=proto_tree_add_ether(fh_tree, hf_eth_src, tvb, 6, 6, src_addr);
+ if(addr_item){
+ addr_tree = proto_item_add_subtree(addr_item, ett_addr);
+ }
+ proto_tree_add_ether(addr_tree, hf_eth_addr, tvb, 6, 6, src_addr);
+ proto_tree_add_item(addr_tree, hf_eth_ig, tvb, 6, 3, FALSE);
+ proto_tree_add_item(addr_tree, hf_eth_lg, tvb, 6, 3, FALSE);
ethertype(ehdr->type, tvb, ETH_HEADER_SIZE, pinfo, parent_tree, fh_tree, hf_eth_type,
hf_eth_trailer, fcs_len);
}
+}
-end_of_eth:
- tap_queue_packet(eth_tap, pinfo, ehdr);
- return;
+/* -------------- */
+static gboolean check_is_802_2(tvbuff_t *tvb, int fcs_len)
+{
+ volatile gboolean is_802_2;
+ volatile int length;
+ gint captured_length, reported_length;
+
+ is_802_2 = TRUE;
+
+ /* Is there an 802.2 layer? I can tell by looking at the first 2
+ bytes after the 802.3 header. If they are 0xffff, then what
+ follows the 802.3 header is an IPX payload, meaning no 802.2.
+ A non-0xffff value means that there's an 802.2 layer or CCSDS
+ layer inside the 802.3 layer */
+
+ TRY {
+ if (tvb_get_ntohs(tvb, 14) == 0xffff) {
+ is_802_2 = FALSE;
+ }
+ /* Is this a CCSDS payload instead of an 802.2 (LLC)?
+ Check the conditions enabled by the user for CCSDS presence */
+ else if (ccsds_heuristic_length || ccsds_heuristic_version ||
+ ccsds_heuristic_header || ccsds_heuristic_bit) {
+ gboolean CCSDS_len = TRUE;
+ gboolean CCSDS_ver = TRUE;
+ gboolean CCSDS_head = TRUE;
+ gboolean CCSDS_bit = TRUE;
+ /* See if the reported payload size matches the
+ size contained in the CCSDS header. */
+ if (ccsds_heuristic_length) {
+ /* The following technique to account for FCS
+ is copied from packet-ieee8023.c dissect_802_3() */
+ length = tvb_get_ntohs(tvb, 12);
+ reported_length = tvb_reported_length_remaining(tvb, ETH_HEADER_SIZE);
+ if (fcs_len > 0) {
+ if (reported_length >= fcs_len)
+ reported_length -= fcs_len;
+ }
+ /* Make sure the length in the 802.3 header doesn't go past the end of
+ the payload. */
+ if (length > reported_length) {
+ length = reported_length;
+ }
+ /* Only allow inspection of 'length' number of bytes. */
+ captured_length = tvb_length_remaining(tvb, ETH_HEADER_SIZE);
+ if (captured_length > length)
+ captured_length = length;
+
+ /* Check if payload is large enough to contain a CCSDS header */
+ if (captured_length >= 6) {
+ /* Compare length to packet length contained in CCSDS header. */
+ if (length != 7 + tvb_get_ntohs(tvb, ETH_HEADER_SIZE + 4))
+ CCSDS_len = FALSE;
+ }
+ }
+ /* Check if CCSDS Version number (first 3 bits of payload) is zero */
+ if ((ccsds_heuristic_version) && (tvb_get_bits8(tvb, 8*ETH_HEADER_SIZE, 3)!=0))
+ CCSDS_ver = FALSE;
+ /* Check if Secondary Header Flag (4th bit of payload) is set to one. */
+ if ((ccsds_heuristic_header) && (tvb_get_bits8(tvb, 8*ETH_HEADER_SIZE + 4, 1)!=1))
+ CCSDS_head = FALSE;
+ /* Check if spare bit (1st bit of 7th word of payload) is zero. */
+ if ((ccsds_heuristic_bit) && (tvb_get_bits8(tvb, 8*ETH_HEADER_SIZE + 16*6, 1)!=0))
+ CCSDS_bit = FALSE;
+ /* If all the conditions are true, don't interpret payload as an 802.2 (LLC).
+ * Additional check in packet-802.3.c will distinguish between
+ * IPX and CCSDS packets*/
+ if (CCSDS_len && CCSDS_ver && CCSDS_head && CCSDS_bit)
+ is_802_2 = FALSE;
+ }
+ }
+ CATCH2(BoundsError, ReportedBoundsError) {
+ ; /* do nothing */
+
+ }
+ ENDTRY;
+ return is_802_2;
}
+
/*
* Add an Ethernet trailer - which, for some captures, might be the FCS
* rather than a pad-to-60-bytes trailer.
* it does, maybe it doesn't"), we try to infer whether it has an FCS.
*/
void
-add_ethernet_trailer(proto_tree *fh_tree, int trailer_id, tvbuff_t *tvb,
- tvbuff_t *trailer_tvb, int fcs_len)
+add_ethernet_trailer(packet_info *pinfo, proto_tree *fh_tree, int trailer_id,
+ tvbuff_t *tvb, tvbuff_t *trailer_tvb, int fcs_len)
{
/* If there're some bytes left over, show those bytes as a trailer.
guint trailer_length, trailer_reported_length;
gboolean has_fcs = FALSE;
+ if (dissector_try_heuristic(eth_trailer_subdissector_list, trailer_tvb,
+ pinfo, fh_tree)) {
+ return;
+ }
+
trailer_length = tvb_length(trailer_tvb);
trailer_reported_length = tvb_reported_length(trailer_tvb);
+
if (fcs_len != 0) {
/* If fcs_len is 4, we assume we definitely have an FCS.
Otherwise, then, if the frame is big enough that, if we
"Frame check sequence: 0x%08x [incorrect, should be 0x%08x]",
sent_fcs, fcs);
}
+ trailer_length += 4;
}
+ proto_tree_set_appendix(fh_tree, tvb, tvb_length(tvb) - trailer_length, trailer_length);
}
}
/* Called for the Ethernet Wiretap encapsulation type; pass the FCS length
- reported to us. */
+ reported to us, or, if the "assume_fcs" preference is set, pass 4. */
static void
dissect_eth_maybefcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- dissect_eth_common(tvb, pinfo, tree, pinfo->pseudo_header->eth.fcs_len);
+ dissect_eth_common(tvb, pinfo, tree,
+ eth_assume_fcs ? 4 :
+ pinfo->pseudo_header->eth.fcs_len);
}
/* Called by other dissectors This one's for encapsulated Ethernet
{ &hf_eth_len,
{ "Length", "eth.len", FT_UINT16, BASE_DEC, NULL, 0x0,
- "", HFILL }},
+ NULL, HFILL }},
- /* registered here but handled in ethertype.c */
+ /* registered here but handled in packet-ethertype.c */
{ &hf_eth_type,
{ "Type", "eth.type", FT_UINT16, BASE_HEX, VALS(etype_vals), 0x0,
- "", HFILL }},
+ NULL, HFILL }},
{ &hf_eth_addr,
- { "Source or Destination Address", "eth.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
+ { "Address", "eth.addr", FT_ETHER, BASE_NONE, NULL, 0x0,
"Source or Destination Hardware Address", HFILL }},
{ &hf_eth_trailer,
{ "Trailer", "eth.trailer", FT_BYTES, BASE_NONE, NULL, 0x0,
"Ethernet Trailer or Checksum", HFILL }},
+ { &hf_eth_ig,
+ { "IG bit", "eth.ig", FT_BOOLEAN, 24,
+ TFS(&ig_tfs), 0x010000,
+ "Specifies if this is an individual (unicast) or group (broadcast/multicast) address", HFILL }},
+
+ { &hf_eth_lg,
+ { "LG bit", "eth.lg", FT_BOOLEAN, 24,
+ TFS(&lg_tfs), 0x020000,
+ "Specifies if this is a locally administered or globally unique (IEEE assigned) address", HFILL }}
+
};
static gint *ett[] = {
&ett_ieee8023,
&ett_ether2,
+ &ett_addr
};
module_t *eth_module;
/* subdissector code */
register_heur_dissector_list("eth", &heur_subdissector_list);
+ register_heur_dissector_list("eth.trailer", ð_trailer_subdissector_list);
/* Register configuration preferences */
eth_module = prefs_register_protocol(proto_eth, NULL);
+
+ prefs_register_bool_preference(eth_module, "assume_fcs",
+ "Assume packets have FCS",
+ "Some Ethernet adapters and drivers include the FCS at the end of a packet, others do not. "
+ "The Ethernet dissector attempts to guess whether a captured packet has an FCS, "
+ "but it cannot always guess correctly.",
+ ð_assume_fcs);
+
prefs_register_bool_preference(eth_module, "interpret_as_fw1_monitor",
"Attempt to interpret as FireWall-1 monitor file",
"Whether packets should be interpreted as coming from CheckPoint FireWall-1 monitor file if they look as if they do",
ð_interpret_as_fw1_monitor);
+ prefs_register_static_text_preference(eth_module, "ccsds_heuristic",
+ "These are the conditions to match a payload against in order to determine if this\n"
+ "is a CCSDS (Consultative Committee for Space Data Systems) packet within\n"
+ "an 802.3 packet. A packet is considered as a possible CCSDS packet only if\n"
+ "one or more of the conditions are checked.",
+ "Describe the conditions that must be true for the CCSDS dissector to be called");
+
+ prefs_register_bool_preference(eth_module, "ccsds_heuristic_length",
+ "CCSDS Length in header matches payload size",
+ "Set the condition that must be true for the CCSDS dissector to be called",
+ &ccsds_heuristic_length);
+
+ prefs_register_bool_preference(eth_module, "ccsds_heuristic_version",
+ "CCSDS Version # is zero",
+ "Set the condition that must be true for the CCSDS dissector to be called",
+ &ccsds_heuristic_version);
+
+ prefs_register_bool_preference(eth_module, "ccsds_heuristic_header",
+ "CCSDS Secondary Header Flag is set",
+ "Set the condition that must be true for the CCSDS dissector to be called",
+ &ccsds_heuristic_header);
+
+ prefs_register_bool_preference(eth_module, "ccsds_heuristic_bit",
+ "CCSDS Spare bit is cleared",
+ "Set the condition that must be true for the CCSDS dissector to be called",
+ &ccsds_heuristic_bit);
+
register_dissector("eth_withoutfcs", dissect_eth_withoutfcs, proto_eth);
register_dissector("eth_withfcs", dissect_eth_withfcs, proto_eth);
+ register_dissector("eth", dissect_eth_maybefcs, proto_eth);
eth_tap = register_tap("eth");
}
*/
fw1_handle = find_dissector("fw1");
- eth_maybefcs_handle = create_dissector_handle(dissect_eth_maybefcs,
- proto_eth);
+ eth_maybefcs_handle = find_dissector("eth");
dissector_add("wtap_encap", WTAP_ENCAP_ETHERNET, eth_maybefcs_handle);
eth_withoutfcs_handle = find_dissector("eth_withoutfcs");