Give a bunch of files RCS IDs.
[obnox/wireshark/wip.git] / packet-tr.c
index 465d6535859f59ddb979286fe8c790b749c9401f..3e3396b7a0859dda10b5f6c85c7fc6dde8cb6df4 100644 (file)
@@ -2,22 +2,22 @@
  * Routines for Token-Ring packet disassembly
  * Gilbert Ramirez <gram@alumni.rice.edu>
  *
- * $Id: packet-tr.c,v 1.69 2002/01/21 07:36:44 guy Exp $
+ * $Id: packet-tr.c,v 1.76 2003/02/08 05:31:05 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * 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 <string.h>
 #include <stdio.h>
 #include <glib.h>
 #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;
 static int hf_tr_src = -1;
@@ -63,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
 
@@ -122,8 +127,8 @@ static dissector_handle_t data_handle;
 
 /*
  * DODGY LINUX HACK DODGY LINUX HACK
- * Linux 2.0.x always passes frames to the Token Ring driver for transmission with 
- * 18 bytes padding for source routing information.  Some drivers copy the first 
+ * Linux 2.0.x always passes frames to the Token Ring driver for transmission with
+ * 18 bytes padding for source routing information.  Some drivers copy the first
  * (18 - srlen) bytes up the frame (18 - srlen) bytes thus removing the padding.
  * Other drivers just make a copy of the entire frame and then hack about with it
  * so the frame the sniffer gets is fine (just has extra sr routing).
@@ -134,11 +139,15 @@ static dissector_handle_t data_handle;
  * This only detects frames that we have sent ourselves so if we are packet sniffing
  * on the machine we are watching this is useful.
  * Compare offset 0 with offset x+1 for a length of x bytes for all value of x = 1 to 18
- * if match then Linux driver has done in situ source route compression of the crappy 
+ * if match then Linux driver has done in situ source route compression of the crappy
  * 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)
 {
        const guint8    *data;
@@ -159,10 +168,11 @@ int check_for_old_linux_tvb(tvbuff_t *tvb)
                        return x;
                }
        }
-       return 0;               
+       return 0;
 }
 
-int check_for_old_linux(const u_char * pd)
+static
+int check_for_old_linux(const guchar * pd)
 {
        int x;
        for(x=1;x<=18;x++)
@@ -172,7 +182,7 @@ int check_for_old_linux(const u_char * pd)
                        return x;
                }
        }
-       return 0;               
+       return 0;
 }
 
 
@@ -180,7 +190,7 @@ static void
 add_ring_bridge_pairs(int rcf_len, tvbuff_t*, proto_tree *tree);
 
 void
-capture_tr(const u_char *pd, int offset, int len, packet_counts *ld) {
+capture_tr(const guchar *pd, int offset, int len, packet_counts *ld) {
 
        int                     source_routed = 0;
        int                     frame_type;
@@ -201,7 +211,7 @@ capture_tr(const u_char *pd, int offset, int len, packet_counts *ld) {
        if ((x = check_for_old_linux(pd)))
        {
                /* Actually packet starts x bytes into what we have got but with all
-                  source routing compressed 
+                  source routing compressed
                */
                 /* pd = &pd[x]; */ offset+=x;
        }
@@ -218,24 +228,31 @@ capture_tr(const u_char *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.
-        */
-       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 ) {
+       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 ) {
 
-                               source_routed = 1;
+                                       source_routed = 1;
+                               }
                        }
                }
        }
@@ -248,34 +265,42 @@ capture_tr(const u_char *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;
 
        /* The package is either MAC or LLC */
@@ -313,23 +338,32 @@ 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];
        int                     x;
-       
+
        /* 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);
@@ -339,57 +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);
+       tvb_memcpy(tr_tvb, trh->dst, 2, 6);
+       tvb_memcpy(tr_tvb, trh->src, 8, 6);
 
-
-       memcpy(trn_shost_nonsr, trn_shost, 6);
+       memcpy(trn_shost_nonsr, trh->src, 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[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.
-        */
-       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) {
@@ -400,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);
+       SET_ADDRESS(&pinfo->dst,        AT_ETHER, 6, trh->dst);
 
        /* protocol analysis tree */
        if (tree) {
@@ -453,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);
+               proto_tree_add_ether(tr_tree, hf_tr_src, tr_tvb, 8, 6, trh->src);
+               proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 2, 6, trh->dst);
+               proto_tree_add_ether_hidden(tr_tree, hf_tr_addr, tr_tvb, 8, 6, trh->src);
 
                proto_tree_add_boolean(tr_tree, hf_tr_sr, tr_tvb, 8, 1, source_routed);
 
@@ -531,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
@@ -567,7 +618,7 @@ add_ring_bridge_pairs(int rcf_len, tvbuff_t *tvb, proto_tree *tree)
                size = sprintf(buffer+buff_offset, "-%01X-%03X",brdgnmb,segment);
                proto_tree_add_uint_hidden(tree, hf_tr_rif_ring, tvb, TR_MIN_HEADER_LEN + 3 + j, 2, segment);
                proto_tree_add_uint_hidden(tree, hf_tr_rif_bridge, tvb, TR_MIN_HEADER_LEN + 2 + j, 1, brdgnmb);
-               buff_offset += size;    
+               buff_offset += size;
        }
        proto_tree_add_string(tree, hf_tr_rif, tvb, TR_MIN_HEADER_LEN + 2, rcf_len, buffer);
 
@@ -664,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