Include <time.h> to declare "gmtime()".
[obnox/wireshark/wip.git] / packet-tr.c
index b14e75e6a585e37189f535a2325947fd29cdcaf1..be357ba8cfcb998b1db11523d96635a45a97d897 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for Token-Ring packet disassembly
  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
  *
- * $Id: packet-tr.c,v 1.7 1998/11/12 00:06:38 gram Exp $
+ * $Id: packet-tr.c,v 1.31 1999/11/16 11:43:00 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@unicom.net>
 # include "config.h"
 #endif
 
-#include <gtk/gtk.h>
-
-#include <stdio.h>
-
 #ifdef HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #endif
 
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-
-#include "ethereal.h"
+#include <stdio.h>
+#include <glib.h>
 #include "packet.h"
-#include "etypes.h"
+       
+static int proto_tr = -1;
+static int hf_tr_dst = -1;
+static int hf_tr_src = -1;
+static int hf_tr_sr = -1;
+static int hf_tr_ac = -1;
+static int hf_tr_priority = -1;
+static int hf_tr_frame = -1;
+static int hf_tr_monitor_cnt = -1;
+static int hf_tr_priority_reservation = -1;
+static int hf_tr_fc = -1;
+static int hf_tr_fc_type = -1;
+static int hf_tr_fc_pcf = -1;
+static int hf_tr_rif_bytes = -1;
+static int hf_tr_broadcast = -1;
+static int hf_tr_max_frame_size = -1;
+static int hf_tr_direction = -1;
+static int hf_tr_rif = -1;
+static int hf_tr_rif_ring = -1;
+static int hf_tr_rif_bridge = -1;
+
+static gint ett_token_ring = -1;
+static gint ett_token_ring_ac = -1;
+static gint ett_token_ring_fc = -1;
+
+#define TR_MIN_HEADER_LEN 14
+#define TR_MAX_HEADER_LEN 32
+
+static const true_false_string ac_truth = { "Frame", "Token" };
+
+static const value_string pcf_vals[] = {
+       { 0,    "Normal buffer" },
+       { 1,    "Express buffer" },
+       { 2,    "Purge" },
+       { 3,    "Claim Token" },
+       { 4,    "Beacon" },
+       { 5,    "Active Monitor Present" },
+       { 6,    "Standby Monitor Present" },
+       { 0,    NULL },
+};
+
+static const value_string frame_vals[] = {
+       { 0,    "MAC" },
+       { 1,    "LLC" },
+       { 2,    "Reserved" },
+       { 0,    NULL },
+};
+
+static const value_string broadcast_vals[] = {
+       { 0 << 5,       "Non-broadcast" },
+       { 1 << 5,       "Non-broadcast" },
+       { 2 << 5,       "Non-broadcast" },
+       { 3 << 5,       "Non-broadcast" },
+       { 4 << 5,       "All-routes broadcast" },
+       { 5 << 5,       "All-routes broadcast" },
+       { 6 << 5,       "Single-route broadcast" },
+       { 7 << 5,       "Single-route broadcast" },
+       { 0,            NULL }
+};
+
+static const value_string max_frame_size_vals[] = {
+       { 0,    "516" },
+       { 1,    "1500" },
+       { 2,    "2052" },
+       { 3,    "4472" },
+       { 4,    "8144" },
+       { 5,    "11407" },
+       { 6,    "17800" },
+       { 0,    NULL }
+};
+
+static const value_string direction_vals[] = {
+       { 0,    "From originating station (-->)" },
+       { 128,  "To originating station (<--)" },
+       { 0,    NULL }
+};
+
+/*
+ * 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 
+ * (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).
+ * In the first instance (driver hacking frame in situ) the sniffer gets a garbled
+ * frame.
+ * This function trys to detect this and returns the offset of where
+ * the frame really starts.
+ * 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 
+ * 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).
+ */
+int check_for_old_linux(const u_char * pd)
+{
+       int x;
+       for(x=1;x<=18;x++)
+       {
+               if (memcmp(&pd[0],&pd[x],x) == 0)
+               {
+                       return x;
+               }
+       }
+       return 0;               
+}
 
 static void
-add_ring_bridge_pairs(int rcf_len, const u_char *pd, GtkWidget *tree);
+add_ring_bridge_pairs(int rcf_len, const u_char *pd, int offset, proto_tree *tree);
+
+void
+capture_tr(const u_char *pd, guint32 cap_len, packet_counts *ld) {
+
+       int                     offset = 0;
 
-static char*
-sr_broadcast(u_char val) {
+       int                     source_routed = 0;
+       int                     frame_type;
+       int                     x;
+       guint8                  trn_rif_bytes;
+       guint8                  actual_rif_bytes;
+
+       /* The trn_hdr struct, as separate variables */
+       guint8                  trn_fc;         /* field control field */
+       guint8                  trn_shost[6];   /* source host */
 
-       if (val < 4) {
-               return "Non-broadcast";
+       if (cap_len < TR_MAX_HEADER_LEN) {
+               ld->other++;
+               return;
        }
-       else if (val < 6) {
-               return "All-routes broadcast";
+
+       if ((x = check_for_old_linux(pd)))
+       {
+               /* Actually packet starts x bytes into what we have got but with all
+                  source routing compressed 
+               */
+                /* pd = &pd[x]; */ offset+=x;
        }
-       else {
-               return "Single-route broadcast";
+
+       /* get the data */
+       memcpy(&trn_fc, &pd[offset + 1], sizeof(guint8));
+       memcpy(trn_shost, &pd[offset + 8], 6 * sizeof(guint8));
+
+       frame_type = (trn_fc & 192) >> 6;
+
+       /* 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;
+
+       trn_rif_bytes = pd[offset + 14] & 31;
+
+       /* sometimes we have a RCF but no RIF... half source-routed? */
+       if (!source_routed && trn_rif_bytes > 0) {
+                /* I'll check for 2 bytes of RIF and mark the packet as source
+                 * routed even though I'm not sure _what_ that kind of packet is */
+               if (trn_rif_bytes == 2) {
+                       source_routed = 1;
+               }
+               /* 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.
+                */
+               else if ( (
+                       pd[offset + 0x0e + trn_rif_bytes] == 0xaa &&
+                       pd[offset + 0x0f + trn_rif_bytes] == 0xaa &&
+                       pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
+                         (
+                       pd[offset + 0x0e + trn_rif_bytes] == 0xe0 &&
+                       pd[offset + 0x0f + trn_rif_bytes] == 0xe0) ) {
+
+                       source_routed = 1;
+               }
+
        }
-}
 
-static int
-sr_frame(u_char val) {
+       if (source_routed) {
+               actual_rif_bytes = trn_rif_bytes;
+       }
+       else {
+               trn_rif_bytes = 0;
+               actual_rif_bytes = 0;
+       }
 
-       int rc_frame[7] = { 516, 1500, 2052, 4472, 8144, 11407, 17800 };
+       /* 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 */
+                }
+       }
+       
+       offset += actual_rif_bytes + 14;
 
-       if (val > 6) {
-               return -1;
+       /* The package is either MAC or LLC */
+       switch (frame_type) {
+               /* MAC */
+               case 0:
+                       ld->other++;
+                       break;
+               case 1:
+                       capture_llc(pd, offset, cap_len, ld);
+                       break;
+               default:
+                       /* non-MAC, non-LLC, i.e., "Reserved" */
+                       ld->other++;
+                       break;
        }
-       else return rc_frame[val];
 }
 
 
 void
-dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
-
-       GtkWidget       *fh_tree, *ti;
-       int                     offset = 14;
+dissect_tr(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
 
+       proto_tree      *tr_tree, *bf_tree;
+       proto_item      *ti;
+       int             fixoffset = 0;
        int                     source_routed = 0;
        int                     frame_type;
-       guint8                  trn_rif_bytes;
-       guint8                  actual_rif_bytes;
+       guint8          trn_rif_bytes;
+       guint8          actual_rif_bytes;
 
        /* The trn_hdr struct, as separate variables */
        guint8                  trn_ac;         /* access control field */
@@ -94,28 +289,35 @@ dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
        guint16                 trn_rseg[8];    /* routing registers */
 
        /* non-source-routed version of source addr */
-       guint8                  trn_shost_nonsr[6];
+       static guint8           trn_shost_nonsr[6];
+       int                     x;
+       
+       /* Token-Ring Strings */
+       char *fc[] = { "MAC", "LLC", "Reserved", "Unknown" };
 
+       if (fd->cap_len < TR_MIN_HEADER_LEN) {
+               dissect_data(pd, offset, fd, tree);
+               return;
+       }
+
+       if ((x = check_for_old_linux(pd)))
+       {
+               /* Actually packet starts x bytes into what we have got but with all
+                  source routing compressed. See comment above */
+               offset += x;
+               /* pd = &pd[x]; */
+       }
 
-       /* Token-Ring Strings */
-       char *fc[] = { "MAC", "LLC", "Reserved" };
-       char *fc_pcf[] = {
-               "Normal buffer", "Express buffer", "Purge",
-               "Claim Token", "Beacon", "Active Monitor Present",
-               "Standby Monitor Present" };
-       char *rc_arrow[] = { "-->", "<--" };
-       char *rc_direction[] = { "From originating station",
-               "To originating station" };
 
        /* get the data */
-       memcpy(&trn_ac, &pd[0], sizeof(guint8));
-       memcpy(&trn_fc, &pd[1], sizeof(guint8));
-       memcpy(trn_dhost, &pd[2], 6 * sizeof(guint8));
-       memcpy(trn_shost, &pd[8], 6 * sizeof(guint8));
-       memcpy(&trn_rcf, &pd[14], sizeof(guint16));
-       memcpy(trn_rseg, &pd[16], 8 * sizeof(guint16));
-
-       memcpy(trn_shost_nonsr, &pd[8], 6 * sizeof(guint8));
+       memcpy(&trn_ac, &pd[offset+0], sizeof(guint8));
+       memcpy(&trn_fc, &pd[offset+1], sizeof(guint8));
+       memcpy(trn_dhost, &pd[offset+2], 6 * sizeof(guint8));
+       memcpy(trn_shost, &pd[offset+8], 6 * sizeof(guint8));
+       memcpy(&trn_rcf, &pd[offset+14], sizeof(guint16));
+       memcpy(trn_rseg, &pd[offset+16], 8 * sizeof(guint16));
+
+       memcpy(trn_shost_nonsr, &pd[offset+8], 6 * sizeof(guint8));
        trn_shost_nonsr[0] &= 127;
        frame_type = (trn_fc & 192) >> 6;
 
@@ -123,11 +325,11 @@ dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
                this packet is source-routed */
        source_routed = trn_shost[0] & 128;
 
-       trn_rif_bytes = pd[14] & 31;
+       trn_rif_bytes = pd[offset+14] & 31;
 
        /* sometimes we have a RCF but no RIF... half source-routed? */
        /* I'll check for 2 bytes of RIF and the 0x70 byte */
-       if (!source_routed) {
+       if (!source_routed && trn_rif_bytes > 0) {
                if (trn_rif_bytes == 2) {
                        source_routed = 1;
                }
@@ -139,18 +341,20 @@ dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
                 * my RIF fields.
                 */
                else if ( (
-                       pd[0x0e + trn_rif_bytes] == 0xaa &&
-                       pd[0x0f + trn_rif_bytes] == 0xaa &&
-                       pd[0x10 + trn_rif_bytes] == 0x03) ||
+                       pd[offset + 0x0e + trn_rif_bytes] == 0xaa &&
+                       pd[offset + 0x0f + trn_rif_bytes] == 0xaa &&
+                       pd[offset + 0x10 + trn_rif_bytes] == 0x03) ||
                          (
-                       pd[0x0e + trn_rif_bytes] == 0xe0 &&
-                       pd[0x0f + trn_rif_bytes] == 0xe0) ) {
+                       pd[offset + 0x0e + trn_rif_bytes] == 0xe0 &&
+                       pd[offset + 0x0f + trn_rif_bytes] == 0xe0) ) {
 
                        source_routed = 1;
                }
 /*             else {
-                       printf("0e+%d = %02X   0f+%d = %02X\n", trn_rif_bytes, pd[0x0e + trn_rif_bytes],
-                                       trn_rif_bytes, pd[0x0f + trn_rif_bytes]);
+                       printf("0e+%d = %02X   0f+%d = %02X\n", trn_rif_bytes,
+                                       pd[offset + 0x0e + trn_rif_bytes],
+                                       trn_rif_bytes,
+                                       pd[offset + 0x0f + trn_rif_bytes]);
                } */
 
        }
@@ -169,64 +373,90 @@ dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
        if ((source_routed && trn_rif_bytes == 2 && frame_type == 1) ||
                (!source_routed && frame_type == 1)) {
                /* look for SNAP or IPX only */
-               if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) ||
-                        (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) {
+               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[0x23] == 0 &&
+                       pd[0x24] == 0 &&
+                       pd[0x25] == 0 &&
+                       pd[0x26] == 0x00 &&
+                       pd[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 */
+                }
        }
-       offset += actual_rif_bytes;
 
+       /* XXX - copy it to some buffer associated with "pi", rather than
+          just making "trn_shost_nonsr" static? */
+       SET_ADDRESS(&pi.dl_src, AT_ETHER, 6, &trn_shost_nonsr[0]);
+       SET_ADDRESS(&pi.src, AT_ETHER, 6, &trn_shost_nonsr[0]);
+       SET_ADDRESS(&pi.dl_dst, AT_ETHER, 6, &pd[offset + 2]);
+       SET_ADDRESS(&pi.dst, AT_ETHER, 6, &pd[offset + 2]);
 
        /* information window */
-       if (fd->win_info[COL_NUM]) {
-               strcpy(fd->win_info[COL_DESTINATION], ether_to_str((guint8 *)&pd[2]));
-               strcpy(fd->win_info[COL_SOURCE], ether_to_str(trn_shost_nonsr));
-               strcpy(fd->win_info[COL_PROTOCOL], "TR");
-               sprintf(fd->win_info[COL_INFO], "Token-Ring %s", fc[frame_type]);
-       }
+       if (check_col(fd, COL_PROTOCOL))
+               col_add_str(fd, COL_PROTOCOL, "TR");
+       if (check_col(fd, COL_INFO))
+               col_add_fstr(fd, COL_INFO, "Token-Ring %s", fc[frame_type]);
 
        /* protocol analysis tree */
        if (tree) {
-               ti = add_item_to_tree(GTK_WIDGET(tree), 0, 14 + actual_rif_bytes,
-                 "Token-Ring");
-               fh_tree = gtk_tree_new();
-               add_subtree(ti, fh_tree, ETT_TOKEN_RING);
-               add_item_to_tree(fh_tree, 0, 1,
-                       "Access Control: %s, Priority=%d, Monitor Count=%d, "
-                       "Priority Reservation=%d",
-                       ((trn_ac & 16) >> 4) ? "Frame" : "Token",       /* frame/token */
-                       ((trn_ac & 224) >> 5),                          /* priority */
-                       ((trn_ac & 8) >> 3),                            /* monitor count */
-                       ((trn_ac & 7)));                                /* priority reserv. */
-
-               add_item_to_tree(fh_tree, 1, 1,
-                       "Frame Control: %s, Physical Control=%d (%s)",
-                       fc[frame_type], (trn_fc & 15),
-                       fc_pcf[(trn_fc & 15)]);
-
-               add_item_to_tree(fh_tree, 2, 6, "Destination: %s",
-                       ether_to_str((guint8 *) trn_dhost));
-               add_item_to_tree(fh_tree, 8, 6, "Source: %s",
-                       ether_to_str((guint8 *) trn_shost));
+               /* Create Token-Ring Tree */
+               ti = proto_tree_add_item(tree, proto_tr, offset, 14 + actual_rif_bytes, NULL);
+               tr_tree = proto_item_add_subtree(ti, ett_token_ring);
 
-               if (source_routed) {
-                       add_item_to_tree(fh_tree, 14, 1, "RIF length: %d bytes", trn_rif_bytes);
+               /* Create the Access Control bitfield tree */
+               ti = proto_tree_add_item(tr_tree, hf_tr_ac, offset, 1, trn_ac);
+               bf_tree = proto_item_add_subtree(ti, ett_token_ring_ac);
 
-                       add_item_to_tree(fh_tree, 15, 1,
-                               "%s, up to %d bytes in frame (LF=%d)",
-                               sr_broadcast((pd[14] & 224) >> 5),
-                               sr_frame((pd[15] & 112) >> 4),
-                               (pd[15] & 112) >> 4);
+               proto_tree_add_item(bf_tree, hf_tr_priority, offset, 1, trn_ac);
+               proto_tree_add_item(bf_tree, hf_tr_frame, offset, 1, trn_ac);
+               proto_tree_add_item(bf_tree, hf_tr_monitor_cnt, offset, 1, trn_ac);
+               proto_tree_add_item(bf_tree, hf_tr_priority_reservation, offset, 1, trn_ac);
 
-                       add_item_to_tree(fh_tree, 15, 1,
-                               "Direction: %s (%s)",
-                               rc_direction[(pd[15] & 128) >> 7],
-                               rc_arrow[(pd[15] & 128) >> 7]);
+               /* Create the Frame Control bitfield tree */
+               ti = proto_tree_add_item(tr_tree, hf_tr_fc, offset + 1, 1, trn_fc);
+               bf_tree = proto_item_add_subtree(ti, ett_token_ring_fc);
+
+               proto_tree_add_item(bf_tree, hf_tr_fc_type, offset + 1, 1, trn_fc);
+               proto_tree_add_item(bf_tree, hf_tr_fc_pcf,  offset + 1, 1, trn_fc);
+               proto_tree_add_item(tr_tree, hf_tr_dst, offset + 2, 6, trn_dhost);
+               proto_tree_add_item(tr_tree, hf_tr_src, offset + 8, 6, trn_shost);
+
+               proto_tree_add_item_hidden(tr_tree, hf_tr_sr, offset + 8, 1, source_routed);
+
+               /* non-source-routed version of src addr */
+               proto_tree_add_item_hidden(tr_tree, hf_tr_src, offset + 8, 6, trn_shost_nonsr);
+
+               if (source_routed) {
+                       /* RCF Byte 1 */
+                       proto_tree_add_item(tr_tree, hf_tr_rif_bytes, offset + 14, 1, trn_rif_bytes);
+                       proto_tree_add_item(tr_tree, hf_tr_broadcast, offset + 14, 1, pd[offset + 14] & 224);
+
+                       /* RCF Byte 2 */
+                       proto_tree_add_item(tr_tree, hf_tr_max_frame_size, offset + 15, 1, pd[offset + 15] & 112);
+                       proto_tree_add_item(tr_tree, hf_tr_direction, offset + 15, 1, pd[offset + 15] & 128);
 
                        /* if we have more than 2 bytes of RIF, then we have
                                ring/bridge pairs */
-                       if (trn_rif_bytes > 2) {
-                               add_ring_bridge_pairs(trn_rif_bytes, pd, fh_tree);
+                       if ((trn_rif_bytes > 2) && BYTES_ARE_IN_FRAME(offset + 14, trn_rif_bytes)) {
+                               add_ring_bridge_pairs(trn_rif_bytes,
+                                       pd, offset, tr_tree);
                        }
                }
 
@@ -240,70 +470,163 @@ dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) {
                tcpdump. W/o that, however, I'm guessing that DSAP == SSAP if the
                frame type is LLC.  It's very much a hack. -- Gilbert Ramirez */
                if (actual_rif_bytes > trn_rif_bytes) {
-                       /*printf("trn_rif %d    actual_rif %d\n", trn_rif_bytes, actual_rif_bytes);*/
-                       add_item_to_tree(fh_tree, 14 + trn_rif_bytes, actual_rif_bytes - trn_rif_bytes,
+                       proto_tree_add_text(tr_tree, 14 + trn_rif_bytes, actual_rif_bytes - trn_rif_bytes,
                                "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
                                "is also running a protocol stack.");
                }
-               /*
-               if (source_routed && (trn_rif_bytes == 2) && silly_linux) {
-                       add_item_to_tree(fh_tree, 14 + trn_rif_bytes, 18 - actual_rif_bytes,
-                               "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
-                               "is also running a protocol stack.");
+               if (fixoffset) {
+                       proto_tree_add_text(tr_tree, 14 + 18,8,"Linux 2.0.x fake LLC and SNAP header");
                }
-               else if ((!source_routed) && silly_linux ) {
-                       add_item_to_tree(fh_tree, 14, 18,
-                               "Empty RIF from Linux 2.0.x driver. The sniffing NIC "
-                               "is also running a protocol stack.");
-               }*/
        }
-
-       /* The package is either MAC or LLC */
-       switch (frame_type) {
-               /* MAC */
-               case 0:
-                       dissect_trmac(pd, offset, fd, tree);
-                       break;
-               case 1:
-                       dissect_llc(pd, offset, fd, tree);
-                       break;
-               default:
-                       /* non-MAC, non-LLC, i.e., "Reserved" */
-                       dissect_data(pd, offset, fd, tree);
-                       break;
+       offset += 14 + actual_rif_bytes + fixoffset;
+
+       if (IS_DATA_IN_FRAME(offset)) {
+               /* The package is either MAC or LLC */
+               switch (frame_type) {
+                       /* MAC */
+                       case 0:
+                               dissect_trmac(pd, offset, fd, tree);
+                               break;
+                       case 1:
+                               dissect_llc(pd, offset, fd, tree);
+                               break;
+                       default:
+                               /* non-MAC, non-LLC, i.e., "Reserved" */
+                               dissect_data(pd, offset, fd, tree);
+                               break;
+               }
        }
 }
 
 /* this routine is taken from the Linux net/802/tr.c code, which shows
-ring-bridge paires in the /proc/net/tr_rif virtual file. */
+ring-bridge pairs in the /proc/net/tr_rif virtual file. */
 static void
-add_ring_bridge_pairs(int rcf_len, const u_char *pd, GtkWidget *tree)
+add_ring_bridge_pairs(int rcf_len, const u_char *pd, int offset, proto_tree *tree)
 {
        int     j, size;
-       int     segment, brdgnmb;
-       char    buffer[50];
-       int             buff_offset=0;
+       int     segment, brdgnmb, unprocessed_rif;
+       int     buff_offset=0;
 
-       rcf_len -= 2;
+#define RIF_BYTES_TO_PROCESS 30
 
-       if (rcf_len)
-               rcf_len >>= 1;
+       char    buffer[3 + (RIF_BYTES_TO_PROCESS / 2) * 6 + 1];
 
-       for(j = 1; j < rcf_len; j++) {
+       /* Only process so many  bytes of RIF, as per TR spec, and not overflow
+        * static buffer above */
+       unprocessed_rif = rcf_len - RIF_BYTES_TO_PROCESS;
+       rcf_len = MIN(rcf_len, RIF_BYTES_TO_PROCESS);
+
+       /* Ignore the 2 RCF bytes, since they don't make up the ring/bride pairs */
+       rcf_len -= 2;
+
+       for(j = 1; j < rcf_len - 1; j += 2) {
                if (j==1) {
-                       segment=ntohs(*((unsigned short*)&pd[16])) >> 4;
-                       size = sprintf(buffer,"%03X",segment);
+                       segment=pntohs(&pd[offset + 16]) >> 4;
+                       size = sprintf(buffer, "%03X",segment);
+                       proto_tree_add_item_hidden(tree, hf_tr_rif_ring, offset + 16, 2, segment);
                        buff_offset += size;
                }
-               segment=ntohs(*((unsigned short*)&pd[17+j])) >> 4;
-               brdgnmb=pd[16+j] & 0x0f;
-               size = sprintf(buffer+buff_offset,"-%01X-%03X",brdgnmb,segment);
+               segment=pntohs(&pd[offset+17+j]) >> 4;
+               brdgnmb=pd[offset+16+j] & 0x0f;
+               size = sprintf(buffer+buff_offset, "-%01X-%03X",brdgnmb,segment);
+               proto_tree_add_item_hidden(tree, hf_tr_rif_ring, offset+17+j, 2, segment);
+               proto_tree_add_item_hidden(tree, hf_tr_rif_bridge, offset+16+j, 1, brdgnmb);
                buff_offset += size;    
        }
+       proto_tree_add_item(tree, hf_tr_rif, offset+16, rcf_len, buffer);
 
-       add_item_to_tree(tree, 16, rcf_len << 1,
-               "Ring-Bridge Pairs: %s",
-               buffer);
+       if (unprocessed_rif > 0) {
+               proto_tree_add_text(tree, offset+14+RIF_BYTES_TO_PROCESS, unprocessed_rif,
+                               "Extra RIF bytes beyond spec: %d", unprocessed_rif);
+       }
+}
 
+void
+proto_register_tr(void)
+{
+       static hf_register_info hf[] = {
+               { &hf_tr_ac,
+               { "Access Control",     "tr.ac", FT_UINT8, BASE_HEX, NULL, 0x0,
+                       "" }},
+
+               { &hf_tr_priority,
+               { "Priority",           "tr.priority", FT_UINT8, BASE_DEC, NULL, 0xe0,
+                       "" }},
+
+               { &hf_tr_frame,
+               { "Frame",              "tr.frame", FT_BOOLEAN, 8, TFS(&ac_truth), 0x10,
+                       "" }},
+
+               { &hf_tr_monitor_cnt,
+               { "Monitor Count",      "tr.monitor_cnt", FT_UINT8, BASE_DEC, NULL, 0x08,
+                       "" }},
+
+               { &hf_tr_priority_reservation,
+               { "Priority Reservation","tr.priority_reservation", FT_UINT8, BASE_DEC, NULL, 0x07,
+                       "" }},
+
+               { &hf_tr_fc,
+               { "Frame Control",      "tr.fc", FT_UINT8, BASE_HEX, NULL, 0x0,
+                       "" }},
+
+               { &hf_tr_fc_type,
+               { "Frame Type",         "tr.frame_type", FT_UINT8, BASE_DEC, VALS(frame_vals), 0xc0,
+                       "" }},
+
+               { &hf_tr_fc_pcf,
+               { "Frame PCF",          "tr.frame_pcf", FT_UINT8, BASE_DEC, VALS(pcf_vals), 0x0f,
+                       "" }},
+
+               { &hf_tr_dst,
+               { "Destination",        "tr.dst", FT_ETHER, BASE_NONE,  NULL, 0x0,
+                       "Destination Hardware Address" }},
+
+               { &hf_tr_src,
+               { "Source",             "tr.src", FT_ETHER, BASE_NONE, NULL, 0x0,
+                       "Source Hardware Address" }},
+
+               { &hf_tr_sr,
+               { "Source Routed",      "tr.sr", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+                       "Source Routed" }},
+
+               { &hf_tr_rif_bytes,
+               { "RIF Bytes",          "tr.rif_bytes", FT_UINT8, BASE_DEC, NULL, 0x0,
+                       "Number of bytes in Routing Information Fields, including "
+                       "the two bytes of Routing Control Field" }},
+
+               { &hf_tr_broadcast,
+               { "Broadcast Type",     "tr.broadcast", FT_UINT8, BASE_DEC, VALS(broadcast_vals), 0x0,
+                       "Type of Token-Ring Broadcast" }},
+
+               { &hf_tr_max_frame_size,
+               { "Maximum Frame Size", "tr.max_frame_size", FT_UINT8, BASE_DEC, VALS(max_frame_size_vals),
+                       0x0,
+                       "" }},
+
+               { &hf_tr_direction,
+               { "Direction",          "tr.direction", FT_UINT8, BASE_DEC, VALS(direction_vals), 0x0,
+                       "Direction of RIF" }},
+
+               { &hf_tr_rif,
+               { "Ring-Bridge Pairs",  "tr.rif", FT_STRING, BASE_NONE, NULL, 0x0,
+                       "String representing Ring-Bridge Pairs" }},
+
+               { &hf_tr_rif_ring,
+               { "RIF Ring",           "tr.rif.ring", FT_UINT16, BASE_HEX, NULL, 0x0,
+                       "" }},
+
+               { &hf_tr_rif_bridge,
+               { "RIF Bridge",         "tr.rif.bridge", FT_UINT8, BASE_HEX, NULL, 0x0,
+                       "" }},
+       };
+       static gint *ett[] = {
+               &ett_token_ring,
+               &ett_token_ring_ac,
+               &ett_token_ring_fc,
+       };
+
+       proto_tr = proto_register_protocol("Token-Ring", "tr");
+       proto_register_field_array(proto_tr, hf, array_length(hf));
+       proto_register_subtree_array(ett, array_length(ett));
 }