Fix for bug 5422:
[obnox/wireshark/wip.git] / epan / dissectors / packet-sll.c
index 598a2d80a183489eb659d9566500529151f9aac2..902e53db0acb751f9152c17542a5f08b4bb6f626 100644 (file)
@@ -26,8 +26,6 @@
 # include "config.h"
 #endif
 
-#include <stdio.h>
-#include <string.h>
 #include <glib.h>
 #include <epan/arptypes.h>
 #include <epan/prefs.h>
@@ -35,7 +33,9 @@
 #include "packet-sll.h"
 #include "packet-ipx.h"
 #include "packet-llc.h"
+#include "packet-eth.h"
 #include "packet-ppp.h"
+#include "packet-gre.h"
 #include <epan/addr_resolv.h>
 #include <epan/etypes.h>
 
@@ -47,6 +47,7 @@ static int hf_sll_src_eth = -1;
 static int hf_sll_src_ipv4 = -1;
 static int hf_sll_src_other = -1;
 static int hf_sll_ltype = -1;
+static int hf_sll_gretype = -1;
 static int hf_sll_etype = -1;
 static int hf_sll_trailer = -1;
 
@@ -76,24 +77,16 @@ static const value_string packet_type_vals[] = {
        { 0,                    NULL }
 };
 
-/*
- * The LINUX_SLL_ values for "sll_protocol".
- */
-#define LINUX_SLL_P_802_3      0x0001  /* Novell 802.3 frames without 802.2 LLC header */
-#define LINUX_SLL_P_802_2      0x0004  /* 802.2 frames (not D/I/X Ethernet) */
-#define LINUX_SLL_P_PPPHDLC    0x0007  /* PPP HDLC frames */
-
 static const value_string ltype_vals[] = {
        { LINUX_SLL_P_802_3,    "Raw 802.3" },
+       { LINUX_SLL_P_ETHERNET, "Ethernet" },
        { LINUX_SLL_P_802_2,    "802.2 LLC" },
        { LINUX_SLL_P_PPPHDLC,  "PPP (HDLC)" },
        { 0,                    NULL }
 };
 
+static dissector_table_t sll_linux_dissector_table;
 static dissector_table_t gre_dissector_table;
-static dissector_handle_t ipx_handle;
-static dissector_handle_t llc_handle;
-static dissector_handle_t ppphdlc_handle;
 static dissector_handle_t data_handle;
 
 void
@@ -120,6 +113,13 @@ capture_sll(const guchar *pd, int len, packet_counts *ld)
                        capture_llc(pd, len, SLL_HEADER_SIZE, ld);
                        break;
 
+               case LINUX_SLL_P_ETHERNET:
+                       /*
+                        * Ethernet.
+                        */
+                       capture_eth(pd, SLL_HEADER_SIZE, len, ld);
+                       break;
+
                case LINUX_SLL_P_802_3:
                        /*
                         * Novell IPX inside 802.3 with no 802.2 LLC
@@ -154,10 +154,8 @@ dissect_sll(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        tvbuff_t *next_tvb;
        proto_tree *fh_tree = NULL;
 
-       if (check_col(pinfo->cinfo, COL_PROTOCOL))
-               col_set_str(pinfo->cinfo, COL_PROTOCOL, "SLL");
-       if (check_col(pinfo->cinfo, COL_INFO))
-               col_clear(pinfo->cinfo, COL_INFO);
+       col_set_str(pinfo->cinfo, COL_PROTOCOL, "SLL");
+       col_clear(pinfo->cinfo, COL_INFO);
 
        pkttype = tvb_get_ntohs(tvb, 0);
 
@@ -218,16 +216,18 @@ dissect_sll(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                            6, 6, src);
                }
                break;
+       case 0:
+               break;
        default:
                if (tree) {
                        proto_tree_add_item(fh_tree, hf_sll_src_other, tvb,
-                           6, halen, FALSE);
+                           6, halen > 8 ? 8 : halen, FALSE);
                }
                break;
        }
 
        protocol = tvb_get_ntohs(tvb, 14);
-       next_tvb = tvb_new_subset(tvb, SLL_HEADER_SIZE, -1, -1);
+       next_tvb = tvb_new_subset_remaining(tvb, SLL_HEADER_SIZE);
        if (protocol <= 1536) { /* yes, 1536 - that's how Linux does it */
                /*
                 * "proto" is *not* a length field, it's a Linux internal
@@ -239,37 +239,15 @@ dissect_sll(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                proto_tree_add_uint(fh_tree, hf_sll_ltype, tvb, 14, 2,
                    protocol);
 
-               switch (protocol) {
-
-               case LINUX_SLL_P_802_2:
-                       /*
-                        * 802.2 LLC.
-                        */
-                       call_dissector(llc_handle, next_tvb, pinfo, tree);
-                       break;
-
-               case LINUX_SLL_P_802_3:
-                       /*
-                        * Novell IPX inside 802.3 with no 802.2 LLC
-                        * header.
-                        */
-                       call_dissector(ipx_handle, next_tvb, pinfo, tree);
-                       break;
-
-               case LINUX_SLL_P_PPPHDLC:
-                       /*
-                        * PPP HDLC
-                        */
-                       call_dissector(ppphdlc_handle, next_tvb, pinfo, tree);
-                       break;
-
-               default:
+               if(!dissector_try_port(sll_linux_dissector_table, protocol,
+                       next_tvb, pinfo, tree)) {
                        call_dissector(data_handle, next_tvb, pinfo, tree);
-                       break;
                }
        } else {
                switch (hatype) {
                case ARPHRD_IPGRE:
+                       proto_tree_add_uint(fh_tree, hf_sll_gretype, tvb, 14, 2,
+                           protocol);
                        dissector_try_port(gre_dissector_table,
                                           protocol, next_tvb, pinfo, tree);
                        break;
@@ -287,16 +265,16 @@ proto_register_sll(void)
        static hf_register_info hf[] = {
                { &hf_sll_pkttype,
                { "Packet type",        "sll.pkttype", FT_UINT16, BASE_DEC,
-                 VALS(packet_type_vals), 0x0, "Packet type", HFILL }},
+                 VALS(packet_type_vals), 0x0, NULL, HFILL }},
 
                /* ARP hardware type?  With Linux extensions? */
                { &hf_sll_hatype,
                { "Link-layer address type",    "sll.hatype", FT_UINT16, BASE_DEC,
-                 NULL, 0x0, "Link-layer address type", HFILL }},
+                 NULL, 0x0, NULL, HFILL }},
 
                { &hf_sll_halen,
                { "Link-layer address length",  "sll.halen", FT_UINT16, BASE_DEC,
-                 NULL, 0x0, "Link-layer address length", HFILL }},
+                 NULL, 0x0, NULL, HFILL }},
 
                /* Source address if it's an Ethernet-type address */
                { &hf_sll_src_eth,
@@ -310,7 +288,7 @@ proto_register_sll(void)
 
                /* Source address if it's not an Ethernet-type address */
                { &hf_sll_src_other,
-               { "Source",     "sll.src.other", FT_BYTES, BASE_HEX, NULL, 0x0,
+               { "Source",     "sll.src.other", FT_BYTES, BASE_NONE, NULL, 0x0,
                        "Source link-layer address", HFILL }},
 
                /* if the protocol field is an internal Linux protocol type */
@@ -318,6 +296,11 @@ proto_register_sll(void)
                { "Protocol",   "sll.ltype", FT_UINT16, BASE_HEX,
                   VALS(ltype_vals), 0x0, "Linux protocol type", HFILL }},
 
+               /* if the protocol field is a GRE protocol type */
+               { &hf_sll_gretype,
+               { "Protocol",   "sll.gretype", FT_UINT16, BASE_HEX,
+                  VALS(gre_typevals), 0x0, "GRE protocol type", HFILL }},
+
                /* registered here but handled in ethertype.c */
                { &hf_sll_etype,
                { "Protocol",   "sll.etype", FT_UINT16, BASE_HEX,
@@ -325,7 +308,7 @@ proto_register_sll(void)
 
                 { &hf_sll_trailer,
                { "Trailer", "sll.trailer", FT_BYTES, BASE_NONE, NULL, 0x0,
-                       "Trailer", HFILL }}
+                       NULL, HFILL }}
        };
        static gint *ett[] = {
                &ett_sll
@@ -335,6 +318,13 @@ proto_register_sll(void)
            "SLL", "sll" );
        proto_register_field_array(proto_sll, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
+
+       sll_linux_dissector_table = register_dissector_table (
+               "sll.ltype",
+               "Linux protocol type",
+               FT_UINT16,
+               BASE_HEX
+       );
 }
 
 void
@@ -346,9 +336,6 @@ proto_reg_handoff_sll(void)
         * Get handles for the IPX and LLC dissectors.
         */
        gre_dissector_table = find_dissector_table("gre.proto");
-       llc_handle = find_dissector("llc");
-       ipx_handle = find_dissector("ipx");
-       ppphdlc_handle = find_dissector("ppp_hdlc");
        data_handle = find_dissector("data");
 
        sll_handle = create_dissector_handle(dissect_sll, proto_sll);