bugfix to a bug reported by Ian Schorr:
[obnox/wireshark/wip.git] / packet-ethertype.c
index b4d7b3ea7bcb0532c50f99605046597e78584add..83bf5bfbc8ee58c7c99402c9fc9a00bc138890ad 100644 (file)
@@ -1,25 +1,24 @@
 /* ethertype.c
  * Routines for calling the right protocol for the ethertype.
  *
- * $Id: packet-ethertype.c,v 1.16 2001/06/14 20:37:07 guy Exp $
+ * $Id: packet-ethertype.c,v 1.46 2004/04/07 06:04:22 guy Exp $
  *
- * Gilbert Ramirez <gram@xiexie.org>
+ * Gilbert Ramirez <gram@alumni.rice.edu>
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
- * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * 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.
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #include <glib.h>
-#include "packet.h"
+#include <epan/packet.h>
+#include "packet-eth.h"
+#include "packet-frame.h"
 #include "packet-ip.h"
+#include "packet-ipv6.h"
 #include "packet-ipx.h"
 #include "packet-vlan.h"
 #include "packet-vines.h"
@@ -44,6 +42,8 @@
 
 static dissector_table_t ethertype_dissector_table;
 
+static dissector_handle_t data_handle;
+
 const value_string etype_vals[] = {
     {ETHERTYPE_IP,             "IP"                            },
     {ETHERTYPE_IPv6,           "IPv6"                          },
@@ -52,15 +52,24 @@ const value_string etype_vals[] = {
     {ETHERTYPE_REVARP,         "RARP"                          },
     {ETHERTYPE_DEC_LB,         "DEC LanBridge"                 },
     {ETHERTYPE_ATALK,          "Appletalk"                     },
+    {ETHERTYPE_SNA,            "SNA-over-Ethernet"             },
     {ETHERTYPE_AARP,           "AARP"                          },
     {ETHERTYPE_IPX,            "Netware IPX/SPX"               },
-    {ETHERTYPE_VINES,          "Vines"                         },
+    {ETHERTYPE_VINES_IP,       "Vines IP"                      },
+    {ETHERTYPE_VINES_ECHO,     "Vines Echo"                    },
     {ETHERTYPE_TRAIN,          "Netmon Train"                  },
     {ETHERTYPE_LOOP,           "Loopback"                      }, /* Ethernet Loopback */
     {ETHERTYPE_WCP,            "Wellfleet Compression Protocol" },
-    {ETHERTYPE_PPPOED,         "PPPoE Discovery"               }, 
-    {ETHERTYPE_PPPOES,         "PPPoE Session"                 }, 
+    {ETHERTYPE_ISMP,           "Cabletron Interswitch Message Protocol" },
+    {ETHERTYPE_ISMP_TBFLOOD,   "Cabletron SFVLAN 1.8 Tag-Based Flood" },
+                               /* for ISMP, see RFC 2641, RFC 2642, RFC 2643 */
+    {ETHERTYPE_PPPOED,         "PPPoE Discovery"               },
+    {ETHERTYPE_PPPOES,         "PPPoE Session"                 },
+    {ETHERTYPE_INTEL_ANS,      "Intel ANS probe"               },
+    {ETHERTYPE_MS_NLB_HEARTBEAT,       "MS NLB heartbeat"      },
     {ETHERTYPE_VLAN,           "802.1Q Virtual LAN"            },
+    {ETHERTYPE_EAPOL,          "802.1X Authentication"         },
+    {ETHERTYPE_RSN_PREAUTH,    "802.11i Pre-Authentication"    },
     {ETHERTYPE_MPLS,           "MPLS label switched packet"    },
     {ETHERTYPE_MPLS_MULTI,     "MPLS multicast label switched packet" },
     {ETHERTYPE_3C_NBP_DGRAM,   "3Com NBP Datagram"             },
@@ -73,36 +82,60 @@ const value_string etype_vals[] = {
     {ETHERTYPE_DEC_CUST,       "DEC Customer use"              },
     {ETHERTYPE_DEC_SCA,                "DEC LAVC/SCA"                  },
     {ETHERTYPE_ETHBRIDGE,      "Transparent Ethernet bridging" },
+    {ETHERTYPE_CGMP,           "Cisco Group Management Protocol" },
+    {ETHERTYPE_SLOW_PROTOCOLS, "Slow Protocols"                },
+    {ETHERTYPE_RTNET,          "RTNET Protocol"                },
+    {ETHERTYPE_RTCFG,          "RTCFG Protocol"                },
+    {ETHERTYPE_PROFINET,       "PROFInet"                },
 
     /*
-     * XXX - is there a standard for running PPP protocols atop
-     * Ethernet, using the PPP protocol type value as the
-     * Ethernet protocol type value?
+     * NDISWAN on Windows translates Ethernet frames from higher-level
+     * protocols into PPP frames to hand to the PPP driver, and translates
+     * PPP frames from the PPP driver to hand to the higher-level protocols.
+     *
+     * Apparently the PPP driver, on at least some versions of Windows,
+     * passes frames for internal-to-PPP protocols up through NDISWAN;
+     * the protocol type field appears to be passed through unchanged
+     * (unlike what's done with, for example, the protocol type field
+     * for IP, which is mapped from its PPP value to its Ethernet value).
+     *
+     * This means that we may see, on Ethernet captures, frames for
+     * protocols internal to PPP, so we list as "Ethernet" protocol
+     * types the PPP protocol types we've seen.
      */
     {PPP_IPCP,                 "PPP IP Control Protocol" },
     {PPP_LCP,                  "PPP Link Control Protocol" },
     {PPP_PAP,                  "PPP Password Authentication Protocol" },
+    {PPP_CCP,                  "PPP Compression Control Protocol" },
     {0,                                NULL                            } };
 
-static void add_trailer(proto_tree *fh_tree, int trailer_id, tvbuff_t *tvb,
-    tvbuff_t *next_tvb, int offset_after_etype, guint length_before);
+static void add_dix_trailer(proto_tree *fh_tree, int trailer_id, tvbuff_t *tvb,
+    tvbuff_t *next_tvb, int offset_after_etype, guint length_before,
+    gint fcs_len);
 
 void
-capture_ethertype(guint16 etype, int offset,
-               const u_char *pd, packet_counts *ld)
+capture_ethertype(guint16 etype, const guchar *pd, int offset, int len,
+                 packet_counts *ld)
 {
   switch (etype) {
+    case ETHERTYPE_ARP:
+      ld->arp++;
+      break;
     case ETHERTYPE_IP:
-      capture_ip(pd, offset, ld);
+      capture_ip(pd, offset, len, ld);
+      break;
+    case ETHERTYPE_IPv6:
+      capture_ipv6(pd, offset, len, ld);
       break;
     case ETHERTYPE_IPX:
-      capture_ipx(pd, offset, ld);
+      capture_ipx(ld);
       break;
     case ETHERTYPE_VLAN:
-      capture_vlan(pd, offset, ld);
+      capture_vlan(pd, offset, len, ld);
       break;
-    case ETHERTYPE_VINES:
-      capture_vines(pd, offset, ld);
+    case ETHERTYPE_VINES_IP:
+    case ETHERTYPE_VINES_ECHO:
+      capture_vines(ld);
       break;
     default:
       ld->other++;
@@ -113,14 +146,15 @@ capture_ethertype(guint16 etype, int offset,
 void
 ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_etype,
                packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree,
-               int etype_id, int trailer_id)
+               int etype_id, int trailer_id, int fcs_len)
 {
        char                    *description;
        tvbuff_t                *next_tvb;
        guint                   length_before;
        volatile gboolean       dissector_found;
-       
-       /* Add to proto_tree */
+       const char              *saved_proto;
+
+       /* Add the Ethernet type to the protocol tree */
        if (tree) {
                proto_tree_add_uint(fh_tree, etype_id, tvb,
                    offset_after_etype - 2, 2, etype);
@@ -135,71 +169,84 @@ ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_etype,
        length_before = tvb_reported_length(next_tvb);
 
        /* Look for sub-dissector, and call it if found.
-          Catch BoundsError and ReportedBoundsError, so that if the
-          reported length of "next_tvb" was reduced by some dissector
-          before an exception was thrown, we can still put in an item
-          for the trailer. */
+          Catch exceptions, so that if the reported length of "next_tvb"
+          was reduced by some dissector before an exception was thrown,
+          we can still put in an item for the trailer. */
+       saved_proto = pinfo->current_proto;
        TRY {
                dissector_found = dissector_try_port(ethertype_dissector_table,
                    etype, next_tvb, pinfo, tree);
        }
-       CATCH2(BoundsError, ReportedBoundsError) {
-               /* Well, somebody threw an exception; that means that a
-                  dissector was found, so we don't need to dissect
-                  the payload as data or update the protocol or info
-                  columns. */
-               dissector_found = TRUE;
+       CATCH(BoundsError) {
+               /* Somebody threw BoundsError, which means that:
 
-               /* Add the trailer, if appropriate. */
-               add_trailer(fh_tree, trailer_id, tvb, next_tvb,
-                   offset_after_etype, length_before);
+                    1) a dissector was found, so we don't need to
+                       dissect the payload as data or update the
+                       protocol or info columns;
 
-               /* Rrethrow the exception, so the "Short Frame" or "Mangled
-                  Frame" indication can be put into the tree. */
-               RETHROW;
+                    2) dissecting the payload found that the packet was
+                       cut off by a snapshot length before the end of
+                       the payload.  The trailer comes after the payload,
+                       so *all* of the trailer is cut off, and we'll
+                       just get another BoundsError if we add the trailer.
 
-               /* XXX - RETHROW shouldn't return. */
-               g_assert_not_reached();
+                  Therefore, we just rethrow the exception so it gets
+                  reported; we don't dissect the trailer or do anything
+                  else. */
+                RETHROW;
+       }
+       CATCH_ALL {
+               /* Somebody threw an exception other than BoundsError, which
+                  means that a dissector was found, so we don't need to
+                  dissect the payload as data or update the protocol or info
+                  columns.  We just show the exception and then drive on
+                  to show the trailer, after noting that a dissector was
+                  found and restoring the protocol value that was in effect
+                  before we called the subdissector. */
+               show_exception(next_tvb, pinfo, tree, EXCEPT_CODE);
+               dissector_found = TRUE;
+               pinfo->current_proto = saved_proto;
        }
        ENDTRY;
 
        if (!dissector_found) {
                /* No sub-dissector found.
                   Label rest of packet as "Data" */
-               dissect_data(next_tvb, 0, pinfo, tree);
+               call_dissector(data_handle,next_tvb, pinfo, tree);
 
                /* Label protocol */
                switch (etype) {
 
                case ETHERTYPE_LOOP:
-                       if (check_col(pinfo->fd, COL_PROTOCOL)) {
-                               col_add_fstr(pinfo->fd, COL_PROTOCOL, "LOOP");
+                       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+                               col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "LOOP");
                        }
                        break;
 
                default:
-                       if (check_col(pinfo->fd, COL_PROTOCOL)) {
-                               col_add_fstr(pinfo->fd, COL_PROTOCOL, "0x%04x",
+                       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+                               col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "0x%04x",
                                    etype);
                        }
                        break;
                }
-               if (check_col(pinfo->fd, COL_INFO)) {
+               if (check_col(pinfo->cinfo, COL_INFO)) {
                        description = match_strval(etype, etype_vals);
                        if (description) {
-                               col_add_fstr(pinfo->fd, COL_INFO, "%s",
+                               col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
                                    description);
                        }
                }
        }
 
-       add_trailer(fh_tree, trailer_id, tvb, next_tvb, offset_after_etype,
-           length_before);
+       add_dix_trailer(fh_tree, trailer_id, tvb, next_tvb, offset_after_etype,
+           length_before, fcs_len);
 }
 
 static void
-add_trailer(proto_tree *fh_tree, int trailer_id, tvbuff_t *tvb,
-    tvbuff_t *next_tvb, int offset_after_etype, guint length_before)
+add_dix_trailer(proto_tree *fh_tree, int trailer_id, tvbuff_t *tvb,
+    tvbuff_t *next_tvb, int offset_after_etype, guint length_before,
+    gint fcs_len)
 {
        guint           length;
        tvbuff_t        *volatile trailer_tvb;
@@ -217,38 +264,37 @@ add_trailer(proto_tree *fh_tree, int trailer_id, tvbuff_t *tvb,
           a trailer. */
        if (length < length_before) {
                /*
-                * Create a tvbuff for the padding.
+                * Is any of the padding present in the tvbuff?
                 */
-               TRY {
+               if (tvb_offset_exists(tvb, offset_after_etype + length)) {
+                       /*
+                        * Yes - create a tvbuff for the padding.
+                        */
                        trailer_tvb = tvb_new_subset(tvb,
                            offset_after_etype + length, -1, -1);
-               }
-               CATCH2(BoundsError, ReportedBoundsError) {
-                       /* The packet doesn't have "length" bytes worth of
-                          captured data left in it.  No trailer to display. */
+               } else {
+                       /*
+                        * No - don't bother showing the trailer.
+                        * XXX - show a Short Frame indication?
+                        */
                        trailer_tvb = NULL;
                }
-               ENDTRY;
        } else
                trailer_tvb = NULL;     /* no trailer */
 
-       /* If there's some bytes left over, and we were given an item ID
-          for a trailer, mark those bytes as a trailer. */
-       if (trailer_tvb) {
-               guint   trailer_length;
-
-               trailer_length = tvb_length(trailer_tvb);
-               if (trailer_length != 0) {
-                       proto_tree_add_item(fh_tree, trailer_id, trailer_tvb, 0,
-                           trailer_length, FALSE);
-               }
-       }
+       add_ethernet_trailer(fh_tree, trailer_id, tvb, trailer_tvb, fcs_len);
 }
 
-
 void
 proto_register_ethertype(void)
 {
        /* subdissector code */
-       ethertype_dissector_table = register_dissector_table("ethertype");
+       ethertype_dissector_table = register_dissector_table("ethertype",
+           "Ethertype", FT_UINT16, BASE_HEX);
+}
+
+void
+proto_reg_handoff_ethertype(void)
+{
+       data_handle = find_dissector("data");
 }