As the gtk2 directory is no longer needed (GTK1 and 2 are using the same sources...
[obnox/wireshark/wip.git] / packet-tr.c
index ad857e4dfd66ab78bcb9339698d8b39fb6859622..79d1130a6a08a6bfa980766d9c5549d6c28c134f 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for Token-Ring packet disassembly
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
- * $Id: packet-tr.c,v 1.73 2002/08/28 21:00:36 jmayer Exp $
+ * $Id$
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -33,6 +33,8 @@
 #include <epan/packet.h>
 #include "packet-tr.h"
 #include "packet-llc.h"
+#include "prefs.h"
+#include "tap.h"
 
 static int proto_tr = -1;
 static int hf_tr_dst = -1;
@@ -59,6 +61,13 @@ static gint ett_token_ring = -1;
 static gint ett_token_ring_ac = -1;
 static gint ett_token_ring_fc = -1;
 
+static int tr_tap = -1;
+
+/*
+ * Check for and attempt to fix Linux link-layer header mangling.
+ */
+static gboolean fix_linux_botches = FALSE;
+
 #define TR_MIN_HEADER_LEN 14
 #define TR_MAX_HEADER_LEN 32
 
@@ -134,6 +143,9 @@ static dissector_handle_t data_handle;
  * Linux 2.0.x frame so the beginning of the real frame is x bytes in.
  * (And this real frame x bytes in looks like a proper TR frame that goes on the wire
  * with none of the Linux idiosyncrasies).
+ *
+ * XXX - there should perhaps be a preference setting to turn this off,
+ * as sometimes it can, and does, get a false hit.
  */
 static
 int check_for_old_linux_tvb(tvbuff_t *tvb)
@@ -216,29 +228,31 @@ capture_tr(const guchar *pd, int offset, int len, packet_counts *ld) {
 
        trn_rif_bytes = pd[offset + 14] & 31;
 
-       /* the Linux 2.0 TR code strips source-route bits in
-        * order to test for SR. This can be removed from most
-        * packets with oltr, but not all. So, I try to figure out
-        * which packets should have been SR here. I'll check to
-        * see if there's a SNAP or IPX field right after
-        * my RIF fields.
-        *
-        * The Linux 2.4.18 code, at least appears to do the
-        * same thing, from a capture I got from somebody running
-        * 2.4.18 (RH 7.1, so perhaps this is a Red Hat
-        * "improvement").
-        */
-       if (!source_routed && trn_rif_bytes > 0) {
-               if (pd[offset + 0x0e] != pd[offset + 0x0f]) {
-                       first2_sr = pntohs(&pd[offset + 0xe0 + trn_rif_bytes]);
-                       if (
-                               (first2_sr == 0xaaaa &&
-                               pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
+       if (fix_linux_botches) {
+               /* the Linux 2.0 TR code strips source-route bits in
+                * order to test for SR. This can be removed from most
+                * packets with oltr, but not all. So, I try to figure out
+                * which packets should have been SR here. I'll check to
+                * see if there's a SNAP or IPX field right after
+                * my RIF fields.
+                *
+                * The Linux 2.4.18 code, at least appears to do the
+                * same thing, from a capture I got from somebody running
+                * 2.4.18 (RH 7.1, so perhaps this is a Red Hat
+                * "improvement").
+                */
+               if (!source_routed && trn_rif_bytes > 0) {
+                       if (pd[offset + 0x0e] != pd[offset + 0x0f]) {
+                               first2_sr = pntohs(&pd[offset + 0xe0 + trn_rif_bytes]);
+                               if (
+                                       (first2_sr == 0xaaaa &&
+                                       pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
 
-                               first2_sr == 0xe0e0 ||
-                               first2_sr == 0xe0aa ) {
+                                       first2_sr == 0xe0e0 ||
+                                       first2_sr == 0xe0aa ) {
 
-                               source_routed = 1;
+                                       source_routed = 1;
+                               }
                        }
                }
        }
@@ -251,32 +265,40 @@ capture_tr(const guchar *pd, int offset, int len, packet_counts *ld) {
                actual_rif_bytes = 0;
        }
 
-       /* this is a silly hack for Linux 2.0.x. Read the comment below,
-       in front of the other #ifdef linux. If we're sniffing our own NIC,
-        we get a full RIF, sometimes with garbage */
-       if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
-               (!source_routed && frame_type == 1)) {
-               /* look for SNAP or IPX only */
-               if ( (pd[offset + 0x20] == 0xaa && pd[offset + 0x21] == 0xaa && pd[offset + 0x22] == 03) ||
-                        (pd[offset + 0x20] == 0xe0 && pd[offset + 0x21] == 0xe0) ) {
-                       actual_rif_bytes = 18;
-               } else if (
-                       pd[offset + 0x23] == 0 &&
-                       pd[offset + 0x24] == 0 &&
-                       pd[offset + 0x25] == 0 &&
-                       pd[offset + 0x26] == 0x00 &&
-                       pd[offset + 0x27] == 0x11) {
-
-                        actual_rif_bytes = 18;
-
-                       /* Linux 2.0.x also requires drivers pass up a fake SNAP and LLC header before th
-                          real LLC hdr for all Token Ring frames that arrive with DSAP and SSAP != 0xAA
-                          (i.e. for non SNAP frames e.g. for Netware frames)
-                          the fake SNAP header has the ETH_P_TR_802_2 ether type (0x0011) and the protocol id
-                          bytes as zero frame looks like :-
-                          TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data */
-                       offset += 8; /* Skip fake LLC and SNAP */
-                }
+       if (fix_linux_botches) {
+               /* this is a silly hack for Linux 2.0.x. Read the comment
+                * below, in front of the other #ifdef linux.
+                * If we're sniffing our own NIC, we get a full RIF,
+                * sometimes with garbage
+                */
+               if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
+                       (!source_routed && frame_type == 1)) {
+                       /* look for SNAP or IPX only */
+                       if ( (pd[offset + 0x20] == 0xaa && pd[offset + 0x21] == 0xaa && pd[offset + 0x22] == 03) ||
+                                (pd[offset + 0x20] == 0xe0 && pd[offset + 0x21] == 0xe0) ) {
+                               actual_rif_bytes = 18;
+                       } else if (
+                               pd[offset + 0x23] == 0 &&
+                               pd[offset + 0x24] == 0 &&
+                               pd[offset + 0x25] == 0 &&
+                               pd[offset + 0x26] == 0x00 &&
+                               pd[offset + 0x27] == 0x11) {
+
+                               actual_rif_bytes = 18;
+
+                              /* Linux 2.0.x also requires drivers pass up
+                               * a fake SNAP and LLC header before the
+                               * real LLC hdr for all Token Ring frames
+                               * that arrive with DSAP and SSAP != 0xAA
+                               * (i.e. for non SNAP frames e.g. for Netware
+                               * frames) the fake SNAP header has the
+                               * ETH_P_TR_802_2 ether type (0x0011) and the protocol id
+                               * bytes as zero frame looks like :-
+                               * TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data
+                               */
+                              offset += 8; /* Skip fake LLC and SNAP */
+                       }
+               }
        }
 
        offset += actual_rif_bytes + TR_MIN_HEADER_LEN;
@@ -316,11 +338,9 @@ dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        volatile guint16        first2_sr;
        tvbuff_t                *volatile tr_tvb;
 
-       /* The trn_hdr struct, as separate variables */
-       guint8                  trn_ac;         /* access control field */
-       guint8                  trn_fc;         /* field control field */
-       const guint8            *trn_dhost;     /* destination host */
-       const guint8            *trn_shost;     /* source host */
+       static tr_hdr trh_arr[4];
+       static int trh_current=0;
+       tr_hdr *trh;
 
        /* non-source-routed version of source addr */
        static guint8           trn_shost_nonsr[6];
@@ -329,10 +349,21 @@ dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        /* Token-Ring Strings */
        char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" };
 
+
+       trh_current++;
+       if(trh_current==4){
+               trh_current=0;
+       }
+       trh=&trh_arr[trh_current];
+
        if (check_col(pinfo->cinfo, COL_PROTOCOL))
                col_set_str(pinfo->cinfo, COL_PROTOCOL, "TR");
 
-       if ((x = check_for_old_linux_tvb((tvbuff_t*) tvb))) {
+       if (fix_linux_botches)
+               x = check_for_old_linux_tvb((tvbuff_t*) tvb);
+       else
+               x = 0;
+       if (x != 0) {
                /* Actually packet starts x bytes into what we have got but with all
                   source routing compressed. See comment above */
                tr_tvb = tvb_new_subset((tvbuff_t*) tvb, x, -1, -1);
@@ -342,62 +373,63 @@ dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
 
        /* Get the data */
-       trn_fc          = tvb_get_guint8(tr_tvb, 1);
-       trn_dhost       = tvb_get_ptr(tr_tvb, 2, 6);
-       trn_shost       = tvb_get_ptr(tr_tvb, 8, 6);
-
+       trh->fc         = tvb_get_guint8(tr_tvb, 1);
+       SET_ADDRESS(&trh->src,  AT_ETHER, 6, tvb_get_ptr(tr_tvb, 8, 6));
+       SET_ADDRESS(&trh->dst,  AT_ETHER, 6, tvb_get_ptr(tr_tvb, 2, 6));
 
-       memcpy(trn_shost_nonsr, trn_shost, 6);
+       memcpy(trn_shost_nonsr, trh->src.data, 6);
        trn_shost_nonsr[0] &= 127;
-       frame_type = (trn_fc & 192) >> 6;
+       frame_type = (trh->fc & 192) >> 6;
 
        if (check_col(pinfo->cinfo, COL_INFO))
                col_add_fstr(pinfo->cinfo, COL_INFO, "Token-Ring %s", fc[frame_type]);
 
        /* if the high bit on the first byte of src hwaddr is 1, then
                this packet is source-routed */
-       source_routed = trn_shost[0] & 128;
+       source_routed = trh->src.data[0] & 128;
 
        trn_rif_bytes = tvb_get_guint8(tr_tvb, 14) & 31;
 
-       /* the Linux 2.0 TR code strips source-route bits in
-        * order to test for SR. This can be removed from most
-        * packets with oltr, but not all. So, I try to figure out
-        * which packets should have been SR here. I'll check to
-        * see if there's a SNAP or IPX field right after
-        * my RIF fields.
-        *
-        * The Linux 2.4.18 code, at least appears to do the
-        * same thing, from a capture I got from somebody running
-        * 2.4.18 (RH 7.1, so perhaps this is a Red Hat
-        * "improvement").
-        */
-       if (frame_type == 1 && !source_routed && trn_rif_bytes > 0) {
-               TRY {
-
-                       c1_nonsr = tvb_get_guint8(tr_tvb, 14);
-                       c2_nonsr = tvb_get_guint8(tr_tvb, 15);
-
-                       if (c1_nonsr != c2_nonsr) {
-
-                               first2_sr = tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e);
-
-                               if ( ( first2_sr == 0xaaaa &&
-                                       tvb_get_guint8(tr_tvb, trn_rif_bytes + 0x10) == 0x03)   ||
-
-                                       first2_sr == 0xe0e0 ||
-                                       first2_sr == 0xe0aa ) {
-
-                                       source_routed = 1;
+       if (fix_linux_botches) {
+               /* the Linux 2.0 TR code strips source-route bits in
+                * order to test for SR. This can be removed from most
+                * packets with oltr, but not all. So, I try to figure out
+                * which packets should have been SR here. I'll check to
+                * see if there's a SNAP or IPX field right after
+                * my RIF fields.
+                *
+                * The Linux 2.4.18 code, at least appears to do the
+                * same thing, from a capture I got from somebody running
+                * 2.4.18 (RH 7.1, so perhaps this is a Red Hat
+                * "improvement").
+                */
+               if (frame_type == 1 && !source_routed && trn_rif_bytes > 0) {
+                       TRY {
+
+                               c1_nonsr = tvb_get_guint8(tr_tvb, 14);
+                               c2_nonsr = tvb_get_guint8(tr_tvb, 15);
+
+                               if (c1_nonsr != c2_nonsr) {
+
+                                       first2_sr = tvb_get_ntohs(tr_tvb, trn_rif_bytes + 0x0e);
+
+                                       if ( ( first2_sr == 0xaaaa &&
+                                               tvb_get_guint8(tr_tvb, trn_rif_bytes + 0x10) == 0x03)   ||
+
+                                               first2_sr == 0xe0e0 ||
+                                               first2_sr == 0xe0aa ) {
+
+                                               source_routed = 1;
+                                       }
                                }
                        }
+                       CATCH(BoundsError) {
+                               /* We had no information beyond the TR header. Just assume
+                                * this is a normal (non-Linux) TR header. */
+                               ;
+                       }
+                       ENDTRY;
                }
-               CATCH(BoundsError) {
-                       /* We had no information beyond the TR header. Just assume
-                        * this is a normal (non-Linux) TR header. */
-                       ;
-               }
-               ENDTRY;
        }
 
        if (source_routed) {
@@ -408,51 +440,60 @@ dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                actual_rif_bytes = 0;
        }
 
-       /* this is a silly hack for Linux 2.0.x. Read the comment below,
-       in front of the other #ifdef linux. If we're sniffing our own NIC,
-        we get a full RIF, sometimes with garbage */
-       TRY {
-               if (frame_type == 1 && ( (source_routed && trn_rif_bytes == 2) ||
-                                        !source_routed) ) {
-                       /* look for SNAP or IPX only */
-                       if (
-                               (tvb_get_ntohs(tr_tvb, 0x20) == 0xaaaa &&
-                               tvb_get_guint8(tr_tvb, 0x22) == 0x03)
-                        ||
-                               tvb_get_ntohs(tr_tvb, 0x20) == 0xe0e0 ) {
-
-                               actual_rif_bytes = 18;
-                      }
-                       else if (
+       if (fix_linux_botches) {
+               /* this is a silly hack for Linux 2.0.x. Read the comment
+                * below, in front of the other #ifdef linux. If we're
+                * sniffing our own NIC, we get a full RIF, sometimes with
+                * garbage
+                */
+               TRY {
+                       if (frame_type == 1 && ( (source_routed && trn_rif_bytes == 2) ||
+                                                !source_routed) ) {
+                               /* look for SNAP or IPX only */
+                               if (
+                                       (tvb_get_ntohs(tr_tvb, 0x20) == 0xaaaa &&
+                                       tvb_get_guint8(tr_tvb, 0x22) == 0x03)
+                                ||
+                                       tvb_get_ntohs(tr_tvb, 0x20) == 0xe0e0 ) {
+
+                                       actual_rif_bytes = 18;
+                               }
+                               else if (
                                        tvb_get_ntohl(tr_tvb, 0x23) == 0 &&
                                        tvb_get_guint8(tr_tvb, 0x27) == 0x11) {
 
-                               actual_rif_bytes = 18;
-
-                              /* Linux 2.0.x also requires drivers pass up a fake SNAP and LLC header before th
-                                 real LLC hdr for all Token Ring frames that arrive with DSAP and SSAP != 0xAA
-                                 (i.e. for non SNAP frames e.g. for Netware frames)
-                                 the fake SNAP header has the ETH_P_TR_802_2 ether type (0x0011) and the protocol id
-                                 bytes as zero frame looks like :-
-                                 TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data */
-                              fixoffset += 8; /* Skip fake LLC and SNAP */
+                                       actual_rif_bytes = 18;
+
+                                      /* Linux 2.0.x also requires drivers
+                                       * pass up a fake SNAP and LLC header
+                                       * before the real LLC hdr for all
+                                       * Token Ring frames that arrive with
+                                       * DSAP and SSAP != 0xAA
+                                       * (i.e. for non SNAP frames e.g. for
+                                       * Netware frames)
+                                       * the fake SNAP header has the
+                                       * ETH_P_TR_802_2 ether type (0x0011)
+                                       * and the protocol id bytes as zero frame looks like :-
+                                       * TR Header | Fake LLC | Fake SNAP | Wire LLC | Rest of data
+                                       */
+                                       fixoffset += 8; /* Skip fake LLC and SNAP */
+                               }
                        }
                }
+               CATCH(BoundsError) {
+                       /* We had no information beyond the TR header. Just assume
+                        * this is a normal (non-Linux) TR header. */
+                       ;
+               }
+               ENDTRY;
        }
-       CATCH(BoundsError) {
-               /* We had no information beyond the TR header. Just assume
-                * this is a normal (non-Linux) TR header. */
-               ;
-       }
-       ENDTRY;
-
 
        /* XXX - copy it to some buffer associated with "*pinfo", rather than
           just making "trn_shost_nonsr" static? */
        SET_ADDRESS(&pinfo->dl_src,     AT_ETHER, 6, trn_shost_nonsr);
        SET_ADDRESS(&pinfo->src,        AT_ETHER, 6, trn_shost_nonsr);
-       SET_ADDRESS(&pinfo->dl_dst,     AT_ETHER, 6, trn_dhost);
-       SET_ADDRESS(&pinfo->dst,        AT_ETHER, 6, trn_dhost);
+       SET_ADDRESS(&pinfo->dl_dst,     AT_ETHER, 6, trh->dst.data);
+       SET_ADDRESS(&pinfo->dst,        AT_ETHER, 6, trh->dst.data);
 
        /* protocol analysis tree */
        if (tree) {
@@ -461,25 +502,25 @@ dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                tr_tree = proto_item_add_subtree(ti, ett_token_ring);
 
                /* Create the Access Control bitfield tree */
-               trn_ac = tvb_get_guint8(tr_tvb, 0);
-               ti = proto_tree_add_uint(tr_tree, hf_tr_ac, tr_tvb, 0, 1, trn_ac);
+               trh->ac = tvb_get_guint8(tr_tvb, 0);
+               ti = proto_tree_add_uint(tr_tree, hf_tr_ac, tr_tvb, 0, 1, trh->ac);
                bf_tree = proto_item_add_subtree(ti, ett_token_ring_ac);
 
-               proto_tree_add_uint(bf_tree, hf_tr_priority, tr_tvb, 0, 1, trn_ac);
-               proto_tree_add_boolean(bf_tree, hf_tr_frame, tr_tvb, 0, 1, trn_ac);
-               proto_tree_add_uint(bf_tree, hf_tr_monitor_cnt, tr_tvb, 0, 1, trn_ac);
-               proto_tree_add_uint(bf_tree, hf_tr_priority_reservation, tr_tvb, 0, 1, trn_ac);
+               proto_tree_add_uint(bf_tree, hf_tr_priority, tr_tvb, 0, 1, trh->ac);
+               proto_tree_add_boolean(bf_tree, hf_tr_frame, tr_tvb, 0, 1, trh->ac);
+               proto_tree_add_uint(bf_tree, hf_tr_monitor_cnt, tr_tvb, 0, 1, trh->ac);
+               proto_tree_add_uint(bf_tree, hf_tr_priority_reservation, tr_tvb, 0, 1, trh->ac);
 
                /* Create the Frame Control bitfield tree */
-               ti = proto_tree_add_uint(tr_tree, hf_tr_fc, tr_tvb, 1, 1, trn_fc);
+               ti = proto_tree_add_uint(tr_tree, hf_tr_fc, tr_tvb, 1, 1, trh->fc);
                bf_tree = proto_item_add_subtree(ti, ett_token_ring_fc);
 
-               proto_tree_add_uint(bf_tree, hf_tr_fc_type, tr_tvb, 1, 1, trn_fc);
-               proto_tree_add_uint(bf_tree, hf_tr_fc_pcf, tr_tvb,  1, 1, trn_fc);
-               proto_tree_add_ether(tr_tree, hf_tr_dst, tr_tvb, 2, 6, trn_dhost);
-               proto_tree_add_ether(tr_tree, hf_tr_src, tr_tvb, 8, 6, trn_shost);
-               proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 2, 6, trn_dhost);
-               proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 8, 6, trn_shost);
+               proto_tree_add_uint(bf_tree, hf_tr_fc_type, tr_tvb, 1, 1, trh->fc);
+               proto_tree_add_uint(bf_tree, hf_tr_fc_pcf, tr_tvb,  1, 1, trh->fc);
+               proto_tree_add_ether(tr_tree, hf_tr_dst, tr_tvb, 2, 6, trh->dst.data);
+               proto_tree_add_ether(tr_tree, hf_tr_src, tr_tvb, 8, 6, trh->src.data);
+               proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 2, 6, trh->dst.data);
+               proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 8, 6, trh->src.data);
 
                proto_tree_add_boolean(tr_tree, hf_tr_sr, tr_tvb, 8, 1, source_routed);
 
@@ -539,6 +580,8 @@ dissect_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        call_dissector(data_handle,next_tvb, pinfo, tree);
                        break;
        }
+
+       tap_queue_packet(tr_tap, pinfo, trh);
 }
 
 /* this routine is taken from the Linux net/802/tr.c code, which shows
@@ -672,11 +715,21 @@ proto_register_tr(void)
                &ett_token_ring_ac,
                &ett_token_ring_fc,
        };
+       module_t *tr_module;
 
        proto_tr = proto_register_protocol("Token-Ring", "Token-Ring", "tr");
        proto_register_field_array(proto_tr, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
+
+       /* Register configuration options */
+       tr_module = prefs_register_protocol(proto_tr, NULL);
+       prefs_register_bool_preference(tr_module, "fix_linux_botches",
+           "Attempt to compensate for Linux mangling of the link-layer header",
+           "Whether Linux mangling of the link-layer header should be checked for and worked around",
+           &fix_linux_botches);
+
        register_dissector("tr", dissect_tr, proto_tr);
+       tr_tap=register_tap("tr");
 }
 
 void