From Steve Karg:

Added MS/TP decoding for the WTAP BACnet MS/TP datalink, and added decoding for
BACnet MS/TP datalink from a Cimetrics U+4 which spews SNAP protocol packets.

svn path=/trunk/; revision=25291
This commit is contained in:
Jaap Keuter 2008-05-14 05:44:42 +00:00
parent 44af6ef887
commit 23df06b7a6
6 changed files with 510 additions and 0 deletions

View File

@ -249,6 +249,7 @@ CLEAN_DISSECTOR_SRC = \
packet-chdlc.c \
packet-cigi.c \
packet-cimd.c \
packet-cimetrics.c \
packet-cip.c \
packet-cisco-erspan.c \
packet-cisco-oui.c \
@ -557,6 +558,7 @@ CLEAN_DISSECTOR_SRC = \
packet-msnip.c \
packet-msproxy.c \
packet-msrp.c \
packet-mstp.c \
packet-mtp2.c \
packet-mtp3.c \
packet-mtp3mg.c \
@ -972,6 +974,7 @@ DISSECTOR_INCLUDES = \
packet-mrdisc.h \
packet-msnip.h \
packet-msrp.h \
packet-mstp.h \
packet-mtp3.h \
packet-nbap.h \
packet-ncp-int.h \

View File

@ -0,0 +1,117 @@
/* packet-cimetrics.c
* Routines for Cimetrics LLC OUI dissection
* Copyright 2008 Steve Karg <skarg@users.sourceforge.net> Alabama
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <epan/packet.h>
#include "packet-llc.h"
#include <epan/oui.h>
#include "packet-mstp.h"
/* the U+4 device does MS/TP, uLAN, Modbus */
static const value_string cimetrics_pid_vals[] = {
{ 0x0001, "U+4 MS/TP" },
{ 0, NULL }
};
static dissector_handle_t bacnet_handle;
static dissector_handle_t data_handle;
static int proto_cimetrics_mstp = -1;
static int hf_llc_cimetrics_pid = -1;
static gint ett_cimetrics_mstp = -1;
static int hf_cimetrics_mstp_timer = -1;
static int hf_cimetrics_mstp_value = -1;
static void
dissect_cimetrics_mstp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
proto_item *ti;
proto_tree *subtree;
gint offset = 0;
ti = proto_tree_add_item(tree, proto_cimetrics_mstp, tvb, offset, 9, FALSE);
subtree = proto_item_add_subtree(ti, ett_cimetrics_mstp);
proto_tree_add_item(subtree, hf_cimetrics_mstp_timer, tvb,
offset++, 2, TRUE);
offset++;
proto_tree_add_item(subtree, hf_cimetrics_mstp_value, tvb,
offset++, 1, TRUE);
dissect_mstp(tvb, pinfo, tree, subtree, offset);
}
void
proto_register_cimetrics(void)
{
static hf_register_info hf[] = {
{ &hf_cimetrics_mstp_timer,
{ "Delta Time", "cimetrics_mstp.timer",
FT_UINT16, BASE_DEC, NULL, 0,
"Milliseconds", HFILL }
},
{ &hf_cimetrics_mstp_value,
{ "8-bit value", "cimetrics_mstp.value",
FT_UINT8, BASE_DEC, NULL, 0,
"value", HFILL }
}
};
static hf_register_info hf2 = {
&hf_llc_cimetrics_pid,
{ "PID", "llc.cimetrics_pid",
FT_UINT16, BASE_HEX, VALS(cimetrics_pid_vals), 0,
NULL, HFILL }
};
static gint *ett[] = {
&ett_cimetrics_mstp
};
proto_cimetrics_mstp = proto_register_protocol("Cimetrics MS/TP",
"Cimetrics MS/TP", "cimetrics");
proto_register_field_array(proto_cimetrics_mstp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
register_dissector("cimetrics", dissect_cimetrics_mstp,
proto_cimetrics_mstp);
llc_add_oui(OUI_CIMETRICS, "llc.cimetrics_pid",
"Cimetrics OUI PID", &hf2);
}
void
proto_reg_handoff_cimetrics(void)
{
dissector_handle_t mstp_handle;
mstp_handle = find_dissector("cimetrics");
dissector_add("llc.cimetrics_pid", 1, mstp_handle);
bacnet_handle = find_dissector("bacnet");
data_handle = find_dissector("data");
}

View File

@ -193,6 +193,7 @@ http://www.cisco.com/univercd/cc/td/doc/product/software/ios113ed/113ed_cr/ibm_r
{ OUI_PROFINET, "PROFIBUS Nutzerorganisation e.V." },
{ OUI_SONY_ERICSSON_3, "Sony Ericsson Mobile Communications AB" },
{ OUI_CATENA, "Catena Networks" },
{ OUI_CIMETRICS, "Cimetrics" },
{ OUI_IEEE_802_3, "IEEE 802.3" },
{ OUI_MEDIA_ENDPOINT, "Media (TIA TR-41 Committee)" },
{ OUI_SONY_ERICSSON_4, "Sony Ericsson Mobile Communications AB" },

View File

@ -0,0 +1,324 @@
/* packet-mstp.c
* Routines for BACnet MS/TP datalink dissection
* Copyright 2008 Steve Karg <skarg@users.sourceforge.net> Alabama
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <epan/packet.h>
#include <epan/oui.h>
#include <epan/llcsaps.h>
#include "packet-llc.h"
#include "packet-mstp.h"
/* MS/TP Frame Type */
/* Frame Types 8 through 127 are reserved by ASHRAE. */
#define MSTP_TOKEN 0
#define MSTP_POLL_FOR_MASTER 1
#define MSTP_REPLY_TO_POLL_FOR_MASTER 2
#define MSTP_TEST_REQUEST 3
#define MSTP_TEST_RESPONSE 4
#define MSTP_BACNET_DATA_EXPECTING_REPLY 5
#define MSTP_BACNET_DATA_NOT_EXPECTING_REPLY 6
#define MSTP_REPLY_POSTPONED 7
static const value_string
bacnet_mstp_frame_type_name[] = {
{MSTP_TOKEN, "Token"},
{MSTP_POLL_FOR_MASTER, "Poll For Master"},
{MSTP_REPLY_TO_POLL_FOR_MASTER, "Reply To Poll For Master"},
{MSTP_TEST_REQUEST, "Test_Request"},
{MSTP_TEST_RESPONSE, "Test_Response"},
{MSTP_BACNET_DATA_EXPECTING_REPLY, "BACnet Data Expecting Reply"},
{MSTP_BACNET_DATA_NOT_EXPECTING_REPLY, "BACnet Data Not Expecting Reply"},
{MSTP_REPLY_POSTPONED, "Reply Postponed"},
/* Frame Types 128 through 255: Proprietary Frames */
{0, NULL }
};
static dissector_handle_t bacnet_handle;
static dissector_handle_t data_handle;
static int proto_mstp = -1;
static gint ett_bacnet_mstp = -1;
static int hf_mstp_preamble_55 = -1;
static int hf_mstp_preamble_FF = -1;
static int hf_mstp_frame_type = -1;
static int hf_mstp_frame_destination = -1;
static int hf_mstp_frame_source = -1;
static int hf_mstp_frame_pdu_len = -1;
static int hf_mstp_frame_crc8 = -1;
static int hf_mstp_frame_crc16 = -1;
#if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
/* Accumulate "dataValue" into the CRC in crcValue. */
/* Return value is updated CRC */
/* The ^ operator means exclusive OR. */
/* Note: This function is copied directly from the BACnet standard. */
static guint8 CRC_Calc_Header(
guint8 dataValue,
guint8 crcValue)
{
guint16 crc;
crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
^ (crc << 7);
/* Combine bits shifted out left hand end */
return (crc & 0xfe) ^ ((crc >> 8) & 1);
}
#endif
#if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
/* Accumulate "dataValue" into the CRC in crcValue. */
/* Return value is updated CRC */
/* The ^ operator means exclusive OR. */
/* Note: This function is copied directly from the BACnet standard. */
static guint16 CRC_Calc_Data(
guint8 dataValue,
guint16 crcValue)
{
guint16 crcLow;
crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
return (crcValue >> 8) ^ (crcLow << 8) ^ (crcLow << 3)
^ (crcLow << 12) ^ (crcLow >> 4)
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
}
#endif
/* dissects a BACnet MS/TP frame */
/* preamble 0x55 0xFF is not included in Cimetrics U+4 output */
void
dissect_mstp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
proto_tree *subtree, gint offset)
{
guint8 mstp_frame_type = 0;
guint8 mstp_frame_source = 0;
guint8 mstp_frame_destination = 0;
guint16 mstp_frame_pdu_len = 0;
guint16 mstp_tvb_pdu_len = 0;
tvbuff_t *next_tvb = NULL;
#if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
/* used to calculate the crc value */
guint8 crc8 = 0xFF, framecrc8;
guint16 crc16 = 0xFFFF, framecrc16;
guint8 crcdata, i;
guint16 max_len = 0;
#endif
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet");
if (check_col(pinfo->cinfo, COL_INFO)) {
col_set_str(pinfo->cinfo, COL_INFO, "BACnet MS/TP");
}
mstp_frame_type = tvb_get_guint8(tvb, offset);
mstp_frame_destination = tvb_get_guint8(tvb, offset+1);
mstp_frame_source = tvb_get_guint8(tvb, offset+2);
mstp_frame_pdu_len = tvb_get_ntohs(tvb, offset+3);
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO, " [%02x>%02x] %s",
mstp_frame_source,
mstp_frame_destination,
val_to_str(mstp_frame_type,
bacnet_mstp_frame_type_name,
"Unknown Frame Type"));
}
proto_tree_add_item(subtree, hf_mstp_frame_type, tvb,
offset, 1, TRUE);
proto_tree_add_item(subtree, hf_mstp_frame_destination, tvb,
offset+1, 1, TRUE);
proto_tree_add_item(subtree, hf_mstp_frame_source, tvb,
offset+2, 1, TRUE);
proto_tree_add_item(subtree, hf_mstp_frame_pdu_len, tvb,
offset+3, 2, TRUE);
#if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
/* calculate checksum to validate */
for (i = 0; i < 5; i++) {
crcdata = tvb_get_guint8(tvb, offset+i);
crc8 = CRC_Calc_Header(crcdata, crc8);
}
crc8 = ~crc8;
framecrc8 = tvb_get_guint8(tvb, offset+5);
if (framecrc8 == crc8) {
proto_tree_add_uint_format(subtree, hf_mstp_frame_crc8,
tvb, offset+5, 1, framecrc8,
"Header CRC: 0x%02x [correct]", framecrc8);
} else {
proto_tree_add_uint_format(subtree, hf_mstp_frame_crc8,
tvb, offset+5, 1, framecrc8,
"Header CRC: 0x%02x [incorrect, should be %02x]",
framecrc8, crc8);
}
#else
proto_tree_add_item(subtree, hf_mstp_frame_crc8,
tvb, offset+5, 1, TRUE);
#endif
/* dissect BACnet PDU if there is one */
offset += 6;
mstp_tvb_pdu_len = tvb_length_remaining(tvb, offset);
if (mstp_tvb_pdu_len > 2) {
/* remove the 16-bit crc checksum bytes */
mstp_tvb_pdu_len -= 2;
next_tvb = tvb_new_subset(tvb, offset,
mstp_tvb_pdu_len, mstp_frame_pdu_len);
if ((mstp_frame_type == MSTP_BACNET_DATA_EXPECTING_REPLY) ||
(mstp_frame_type == MSTP_BACNET_DATA_NOT_EXPECTING_REPLY)) {
/* NPDU - call the BACnet NPDU dissector */
call_dissector(bacnet_handle, next_tvb, pinfo, tree);
} else {
/* Unknown function - dissect the payload as data */
call_dissector(data_handle, next_tvb, pinfo, tree);
}
#if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
/* 16-bit checksum - calculate to validate */
max_len = min(mstp_frame_pdu_len, mstp_tvb_pdu_len);
for (i = 0; i < max_len; i++) {
crcdata = tvb_get_guint8(tvb, offset+i);
crc16 = CRC_Calc_Data(crcdata, crc16);
}
crc16 = ~crc16;
/* convert it to on-the-wire format */
crc16 = g_htons(crc16);
/* get the actual CRC from the frame */
framecrc16 = tvb_get_ntohs(tvb, offset+mstp_frame_pdu_len);
if (framecrc16 == crc16) {
proto_tree_add_uint_format(subtree, hf_mstp_frame_crc16,
tvb, offset+mstp_frame_pdu_len, 2, framecrc16,
"Data CRC: 0x%04x [correct]", framecrc16);
} else {
proto_tree_add_uint_format(subtree, hf_mstp_frame_crc16,
tvb, offset+mstp_frame_pdu_len, 2, framecrc16,
"Data CRC: 0x%04x [incorrect, should be %04x]",
framecrc16, crc16);
}
#else
proto_tree_add_item(subtree, hf_mstp_frame_crc16,
tvb, offset+mstp_frame_pdu_len, 2, TRUE);
#endif
}
}
static void
dissect_mstp_wtap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
proto_item *ti;
proto_tree *subtree;
gint offset = 0;
ti = proto_tree_add_item(tree, proto_mstp, tvb, offset, 8, FALSE);
subtree = proto_item_add_subtree(ti, ett_bacnet_mstp);
proto_tree_add_item(subtree, hf_mstp_preamble_55, tvb,
offset, 1, TRUE);
proto_tree_add_item(subtree, hf_mstp_preamble_FF, tvb,
offset+1, 1, TRUE);
dissect_mstp(tvb, pinfo, tree, subtree, offset+2);
}
void
proto_register_mstp(void)
{
static hf_register_info hf[] = {
{ &hf_mstp_preamble_55,
{ "Preamble 55", "mstp.preamble_55",
FT_UINT8, BASE_HEX, NULL, 0,
"MS/TP Preamble 55", HFILL }
},
{ &hf_mstp_preamble_FF,
{ "Preamble FF", "mstp.preamble_FF",
FT_UINT8, BASE_HEX, NULL, 0,
"MS/TP Preamble FF", HFILL }
},
{ &hf_mstp_frame_type,
{ "Frame Type", "mstp.frame_type",
FT_UINT8, BASE_DEC, VALS(bacnet_mstp_frame_type_name), 0,
"MS/TP Frame Type", HFILL }
},
{ &hf_mstp_frame_destination,
{ "Destination Address", "mstp.destination",
FT_UINT8, BASE_DEC, NULL, 0,
"Destination MS/TP MAC Address", HFILL }
},
{ &hf_mstp_frame_source,
{ "Source Address", "mstp.source",
FT_UINT8, BASE_DEC, NULL, 0,
"Source MS/TP MAC Address", HFILL }
},
{ &hf_mstp_frame_pdu_len,
{ "Length", "mstp.length",
FT_UINT16, BASE_DEC, NULL, 0,
"MS/TP Frame Data Length", HFILL }
},
{ &hf_mstp_frame_crc8,
{ "Header CRC", "mstp.header_crc",
FT_UINT8, BASE_HEX, NULL, 0,
"MS/TP Header CRC", HFILL }
},
{ &hf_mstp_frame_crc16,
{ "Data CRC", "mstp.data_crc",
FT_UINT16, BASE_HEX, NULL, 0,
"MS/TP Data CRC", HFILL }
}
};
static gint *ett[] = {
&ett_bacnet_mstp
};
proto_mstp = proto_register_protocol("BACnet MS/TP",
"BACnet MS/TP", "mstp");
proto_register_field_array(proto_mstp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
register_dissector("mstp", dissect_mstp_wtap, proto_mstp);
}
void
proto_reg_handoff_mstp(void)
{
dissector_handle_t mstp_handle;
mstp_handle = find_dissector("mstp");
dissector_add("wtap_encap", WTAP_ENCAP_BACNET_MS_TP, mstp_handle);
bacnet_handle = find_dissector("bacnet");
data_handle = find_dissector("data");
}

View File

@ -0,0 +1,64 @@
/* packet-mstp.h
* Routines for BACnet MS/TP datalink dissection
* Copyright 2008 Steve Karg <skarg@users.sourceforge.net> Alabama
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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.
*/
#ifndef __MSTP_H__
#define __MSTP_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#if HAVE_ICONV
#include <iconv.h>
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <epan/packet.h>
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif
/**
* Dissects the BACnet MS/TP packet after the preamble,
* starting with the MS/TP Frame type octet. Passes
* the PDU, if there is one, to the BACnet dissector.
* @param tvb
* @param pinfo
* @param tree
* @param subtree
* @param offset
* @return none
*/
void
dissect_mstp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *subtree, gint offset);
#endif /* __MSTP_H__ */

View File

@ -46,6 +46,7 @@
#define OUI_SONY_ERICSSON_2 0x000E07 /* Sony Ericsson Mobile Communications AB */
#define OUI_PROFINET 0x000ECF /* PROFIBUS Nutzerorganisation e.V. */
#define OUI_SONY_ERICSSON_3 0x000FDE /* Sony Ericsson Mobile Communications AB */
#define OUI_CIMETRICS 0x001090 /* Cimetrics, Inc. */
#define OUI_IEEE_802_3 0x00120F /* IEEE 802.3 */
#define OUI_MEDIA_ENDPOINT 0x0012BB /* Media (TIA TR-41 Committee) */
#define OUI_SONY_ERICSSON_4 0x0012EE /* Sony Ericsson Mobile Communications AB */