* 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;
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
/*
* 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).
* 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;
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++)
return x;
}
}
- return 0;
+ return 0;
}
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;
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;
}
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;
+ }
}
}
}
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 */
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);
}
/* 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) {
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) {
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);
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
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);
&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