BACNET support, from Hartmut Mueller.
svn path=/trunk/; revision=3214
This commit is contained in:
parent
6556578270
commit
9c1502e3e0
4
AUTHORS
4
AUTHORS
|
@ -551,6 +551,10 @@ Martin Thomas <martin_a_thomas@yahoo.com> {
|
|||
102, containing OSI transport layer PDUs)
|
||||
}
|
||||
|
||||
Hartmut Mueller <hartmut@wendolene.ping.de> {
|
||||
BACNET support
|
||||
}
|
||||
|
||||
Alain Magloire <alainm@rcsm.ece.mcgill.ca> was kind enough to
|
||||
give his permission to use his version of snprintf.c.
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Makefile.am
|
||||
# Automake file for Ethereal
|
||||
#
|
||||
# $Id: Makefile.am,v 1.297 2001/03/30 10:51:48 guy Exp $
|
||||
# $Id: Makefile.am,v 1.298 2001/03/31 10:13:10 guy Exp $
|
||||
#
|
||||
# Ethereal - Network traffic analyzer
|
||||
# By Gerald Combs <gerald@zing.org>
|
||||
|
@ -78,10 +78,13 @@ DISSECTOR_SOURCES = \
|
|||
packet-atalk.c \
|
||||
packet-atm.c \
|
||||
packet-auto_rp.c \
|
||||
packet-bacapp.c \
|
||||
packet-bacnet.c \
|
||||
packet-bgp.c \
|
||||
packet-bootp.c \
|
||||
packet-bootparams.c \
|
||||
packet-bpdu.c \
|
||||
packet-bvlc.c \
|
||||
packet-bxxp.c \
|
||||
packet-cdp.c \
|
||||
packet-cgmp.c \
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## Makefile for building ethereal.exe with Microsoft C and nmake
|
||||
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
|
||||
#
|
||||
# $Id: Makefile.nmake,v 1.90 2001/03/23 21:38:56 guy Exp $
|
||||
# $Id: Makefile.nmake,v 1.91 2001/03/31 10:13:10 guy Exp $
|
||||
|
||||
include config.nmake
|
||||
include <win32.mak>
|
||||
|
@ -31,10 +31,13 @@ DISSECTOR_SOURCES = \
|
|||
packet-atalk.c \
|
||||
packet-atm.c \
|
||||
packet-auto_rp.c \
|
||||
packet-bacapp.c \
|
||||
packet-bacnet.c \
|
||||
packet-bgp.c \
|
||||
packet-bootp.c \
|
||||
packet-bootparams.c \
|
||||
packet-bpdu.c \
|
||||
packet-bvlc.c \
|
||||
packet-bxxp.c \
|
||||
packet-cdp.c \
|
||||
packet-cgmp.c \
|
||||
|
|
|
@ -1083,6 +1083,7 @@ B<http://www.ethereal.com>.
|
|||
Todd Sabin <tas@webspan.net>
|
||||
Eduardo Pérez Ureta <eperez@dei.inf.uc3m.es>
|
||||
Martin Thomas <martin_a_thomas@yahoo.com>
|
||||
Hartmut Mueller <hartmut@wendolene.ping.de>
|
||||
|
||||
Alain Magloire <alainm@rcsm.ece.mcgill.ca> was kind enough to give his
|
||||
permission to use his version of snprintf.c.
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/* packet-bacapp.c
|
||||
* Routines for BACnet (APDU) dissection
|
||||
* Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
|
||||
*
|
||||
* $Id: packet-bacapp.c,v 1.1 2001/03/31 10:13:11 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@unicom.net>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* Copied from README.developer,v 1.23
|
||||
*
|
||||
* 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>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef NEED_SNPRINTF_H
|
||||
# include "snprintf.h"
|
||||
#endif
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
static const char*
|
||||
bacapp_type_name (guint8 bacapp_type){
|
||||
static const char *type_names[] = {
|
||||
"Confirmed-Request-PDU",
|
||||
"Unconfirmed-Request-PDU",
|
||||
"SimpleACK-PDU",
|
||||
"ComplexACK-PDU",
|
||||
"SegmentACK-PDU",
|
||||
"Error-PDU",
|
||||
"Reject-PDU",
|
||||
"Abort-PDU"
|
||||
};
|
||||
return (bacapp_type > 7)? "unknown PDU" : type_names[bacapp_type];
|
||||
}
|
||||
|
||||
static int proto_bacapp = -1;
|
||||
static int hf_bacapp_type = -1;
|
||||
|
||||
static gint ett_bacapp = -1;
|
||||
|
||||
static void
|
||||
dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
||||
{
|
||||
proto_item *ti;
|
||||
proto_tree *bacapp_tree;
|
||||
guint8 offset;
|
||||
guint8 bacapp_type;
|
||||
tvbuff_t *next_tvb;
|
||||
|
||||
pinfo->current_proto = "BACapp";
|
||||
if (check_col(pinfo->fd, COL_PROTOCOL))
|
||||
col_set_str(pinfo->fd, COL_PROTOCOL, "BACnet-APDU");
|
||||
if (check_col(pinfo->fd, COL_INFO))
|
||||
col_add_str(pinfo->fd, COL_INFO, "BACnet APDU ");
|
||||
|
||||
offset = 0;
|
||||
bacapp_type = (tvb_get_guint8(tvb, offset) >> 4) & 0x0f;
|
||||
|
||||
if (check_col(pinfo->fd, COL_INFO))
|
||||
col_append_fstr(pinfo->fd, COL_INFO, "(%s)",
|
||||
bacapp_type_name(bacapp_type));
|
||||
if (tree) {
|
||||
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, tvb_length(tvb), FALSE);
|
||||
|
||||
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
|
||||
|
||||
proto_tree_add_uint_format(bacapp_tree, hf_bacapp_type, tvb,
|
||||
offset, 1, bacapp_type, "APDU Type: %u (%s)", bacapp_type,
|
||||
bacapp_type_name(bacapp_type));
|
||||
offset ++;
|
||||
|
||||
}
|
||||
next_tvb = tvb_new_subset(tvb,offset,-1,-1);
|
||||
dissect_data(next_tvb, 0, pinfo, tree);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
proto_register_bacapp(void)
|
||||
{
|
||||
static hf_register_info hf[] = {
|
||||
{ &hf_bacapp_type,
|
||||
{ "APDU Type", "bacapp.bacapp_type",
|
||||
FT_UINT8, BASE_DEC, NULL, 0xf0, "APDU Type" }
|
||||
},
|
||||
};
|
||||
static gint *ett[] = {
|
||||
&ett_bacapp,
|
||||
};
|
||||
proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU",
|
||||
"BACapp", "bacapp");
|
||||
proto_register_field_array(proto_bacapp, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
}
|
||||
void
|
||||
proto_reg_handoff_bacapp(void)
|
||||
{
|
||||
dissector_add("bacnet_control_net", 0, dissect_bacapp, proto_bacapp);
|
||||
}
|
|
@ -0,0 +1,607 @@
|
|||
/* packet-bacnet.c
|
||||
* Routines for BACnet (NPDU) dissection
|
||||
* Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
|
||||
*
|
||||
* $Id: packet-bacnet.c,v 1.1 2001/03/31 10:13:11 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@unicom.net>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* Copied from README.developer,v 1.23
|
||||
*
|
||||
* 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>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef NEED_SNPRINTF_H
|
||||
# include "snprintf.h"
|
||||
#endif
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
static dissector_table_t bacnet_dissector_table;
|
||||
|
||||
static const char*
|
||||
bacnet_mesgtyp_name (guint8 bacnet_mesgtyp){
|
||||
static const char *type_names[] = {
|
||||
"Who-Is-Router-To-Network",
|
||||
"I-Am-Router-To-Network",
|
||||
"I-Could-Be-Router-To-Network",
|
||||
"Reject-Message-To-Network",
|
||||
"Router-Busy-To-Network",
|
||||
"Router-Available-To-Network",
|
||||
"Initialize-Routing-Table",
|
||||
"Initialize-Routing-Table-Ack",
|
||||
"Establish-Connection-To-Network",
|
||||
"Disconnect-Connection-To-Network"
|
||||
};
|
||||
if(bacnet_mesgtyp < 0x0a) {
|
||||
return type_names[bacnet_mesgtyp];
|
||||
} else {
|
||||
return (bacnet_mesgtyp < 0x80)? "Reserved for Use by ASHRAE" : "Vendor Proprietary Message";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
bacnet_rejectreason_name (guint8 bacnet_rejectreason) {
|
||||
static const char *type_names[] = {
|
||||
"Other error.",
|
||||
"The router is not directly connected to DNET and cannot find a router to DNET on any directly connected network using Who-Is-Router-To-Network messages.",
|
||||
"The router is busy and unable to accept messages for the specified DNET at the present time.",
|
||||
"It is an unknown network layer message type.",
|
||||
"The message is too long to be routed to this DNET.",
|
||||
"The router is no longer directly connected to DNET but can reconnect if requested.",
|
||||
"The router is no longer directly connected to DNET and cannot reconnect even if requested."
|
||||
};
|
||||
return (bacnet_rejectreason > 6)? "Invalid Rejection Reason.": type_names[bacnet_rejectreason];
|
||||
}
|
||||
|
||||
/* Network Layer Control Information */
|
||||
#define BAC_CONTROL_NET 0x80
|
||||
#define BAC_CONTROL_RES1 0x40
|
||||
#define BAC_CONTROL_DEST 0x20
|
||||
#define BAC_CONTROL_RES2 0x10
|
||||
#define BAC_CONTROL_SRC 0x08
|
||||
#define BAC_CONTROL_EXPECT 0x04
|
||||
#define BAC_CONTROL_PRIO_HIGH 0x02
|
||||
#define BAC_CONTROL_PRIO_LOW 0x01
|
||||
|
||||
/* Network Layer Message Types */
|
||||
#define BAC_NET_WHO_R 0x00
|
||||
#define BAC_NET_IAM_R 0x01
|
||||
#define BAC_NET_ICB_R 0x02
|
||||
#define BAC_NET_REJ 0x03
|
||||
#define BAC_NET_R_BUSY 0x04
|
||||
#define BAC_NET_R_AVA 0x05
|
||||
#define BAC_NET_INIT_RTAB 0x06
|
||||
#define BAC_NET_INIT_RTAB_ACK 0x07
|
||||
#define BAC_NET_EST_CON 0x08
|
||||
#define BAC_NET_DISC_CON 0x09
|
||||
|
||||
static const true_false_string control_net_set_high = {
|
||||
"network layer message, message type field present.",
|
||||
"BACnet APDU, message type field absent."
|
||||
};
|
||||
|
||||
static const true_false_string control_res_high = {
|
||||
"Shall be zero, but is one.",
|
||||
"Shall be zero and is zero."
|
||||
};
|
||||
static const true_false_string control_dest_high = {
|
||||
"DNET, DLEN and Hop Count present. If DLEN=0: broadcast, dest. address field absent.",
|
||||
"DNET, DLEN, DADR and Hop Count absent."
|
||||
};
|
||||
|
||||
static const true_false_string control_src_high = {
|
||||
"SNET, SLEN and SADR present, SLEN=0 invalid, SLEN specifies length of SADR",
|
||||
"SNET, SLEN and SADR absent"
|
||||
};
|
||||
|
||||
static const true_false_string control_expect_high = {
|
||||
"BACnet-Confirmed-Request-PDU, a segment of BACnet-ComplexACK-PDU or Network Message expecting a reply present.",
|
||||
"Other than a BACnet-Confirmed-Request-PDU, segment of BACnet-ComplexACK-PDU or network layer message expecting a reply present."
|
||||
};
|
||||
|
||||
static const true_false_string control_prio_high_high = {
|
||||
"Life Safety or Critical Equipment message.",
|
||||
"Not a Life Safety or Critical Equipment message."
|
||||
};
|
||||
|
||||
static const true_false_string control_prio_low_high = {
|
||||
"Urgent message",
|
||||
"Normal message"
|
||||
};
|
||||
|
||||
|
||||
static int proto_bacnet = -1;
|
||||
static int hf_bacnet_version = -1;
|
||||
static int hf_bacnet_control = -1;
|
||||
static int hf_bacnet_control_net = -1;
|
||||
static int hf_bacnet_control_res1 = -1;
|
||||
static int hf_bacnet_control_dest = -1;
|
||||
static int hf_bacnet_control_res2 = -1;
|
||||
static int hf_bacnet_control_src = -1;
|
||||
static int hf_bacnet_control_expect = -1;
|
||||
static int hf_bacnet_control_prio_high = -1;
|
||||
static int hf_bacnet_control_prio_low = -1;
|
||||
static int hf_bacnet_dnet = -1;
|
||||
static int hf_bacnet_dlen = -1;
|
||||
static int hf_bacnet_dadr_eth = -1;
|
||||
static int hf_bacnet_dadr_tmp = -1;
|
||||
static int hf_bacnet_snet = -1;
|
||||
static int hf_bacnet_slen = -1;
|
||||
static int hf_bacnet_sadr_eth = -1;
|
||||
static int hf_bacnet_sadr_tmp = -1;
|
||||
static int hf_bacnet_hopc = -1;
|
||||
static int hf_bacnet_mesgtyp = -1;
|
||||
static int hf_bacnet_vendor = -1;
|
||||
static int hf_bacnet_perf = -1;
|
||||
static int hf_bacnet_rejectreason = -1;
|
||||
static int hf_bacnet_rportnum = -1;
|
||||
static int hf_bacnet_portid = -1;
|
||||
static int hf_bacnet_pinfolen = -1;
|
||||
static int hf_bacnet_pinfo = -1;
|
||||
|
||||
static gint ett_bacnet = -1;
|
||||
static gint ett_bacnet_control = -1;
|
||||
|
||||
static void
|
||||
dissect_bacnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
||||
{
|
||||
proto_item *ti;
|
||||
proto_item *ct;
|
||||
proto_tree *bacnet_tree;
|
||||
proto_tree *control_tree;
|
||||
|
||||
gint offset;
|
||||
guint8 bacnet_version;
|
||||
guint8 bacnet_control;
|
||||
guint8 bacnet_control_net;
|
||||
guint8 bacnet_dlen;
|
||||
guint8 bacnet_slen;
|
||||
guint8 bacnet_mesgtyp;
|
||||
guint8 bacnet_rejectreason;
|
||||
guint8 bacnet_rportnum;
|
||||
guint8 bacnet_pinfolen;
|
||||
guint8 i;
|
||||
guint8 j;
|
||||
tvbuff_t *next_tvb;
|
||||
|
||||
pinfo->current_proto = "BACnet";
|
||||
|
||||
if (check_col(pinfo->fd, COL_PROTOCOL))
|
||||
col_set_str(pinfo->fd, COL_PROTOCOL, "BACnet-NPDU");
|
||||
|
||||
if (check_col(pinfo->fd, COL_INFO))
|
||||
col_set_str(pinfo->fd, COL_INFO, "Building Automation and Control Network NPDU");
|
||||
|
||||
offset = 0;
|
||||
bacnet_version = tvb_get_guint8(tvb, offset);
|
||||
bacnet_control = tvb_get_guint8(tvb, offset+1);
|
||||
bacnet_control_net = tvb_get_guint8(tvb, offset+1) & BAC_CONTROL_NET;
|
||||
bacnet_dlen = 0;
|
||||
bacnet_slen = 0;
|
||||
bacnet_mesgtyp = 0;
|
||||
bacnet_rejectreason = 0;
|
||||
bacnet_rportnum = 0;
|
||||
bacnet_pinfolen =0;
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
if (tree) {
|
||||
|
||||
/* I don't know the length of the NPDU by know. Setting the length after dissection */
|
||||
ti = proto_tree_add_item(tree, proto_bacnet, tvb, 0, 0, FALSE);
|
||||
|
||||
bacnet_tree = proto_item_add_subtree(ti, ett_bacnet);
|
||||
|
||||
proto_tree_add_uint_format(bacnet_tree, hf_bacnet_version, tvb,
|
||||
offset, 1,
|
||||
bacnet_version,"Version: 0x%02x (%s)",bacnet_version,
|
||||
(bacnet_version == 0x01)?"ASHRAE 135-1995":"unknown");
|
||||
offset ++;
|
||||
ct = proto_tree_add_uint_format(bacnet_tree, hf_bacnet_control,
|
||||
tvb, offset, 1,
|
||||
bacnet_control,"Control: 0x%02x",bacnet_control);
|
||||
control_tree = proto_item_add_subtree(ct,
|
||||
ett_bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_net,
|
||||
tvb, offset, 1, bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_res1, tvb,
|
||||
offset, 1, bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_dest, tvb,
|
||||
offset, 1, bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_res2, tvb,
|
||||
offset, 1, bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_src, tvb,
|
||||
offset, 1, bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_expect, tvb,
|
||||
offset, 1, bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_high,
|
||||
tvb, offset, 1, bacnet_control);
|
||||
proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_low,
|
||||
tvb, offset, 1, bacnet_control);
|
||||
offset ++;
|
||||
if (bacnet_control & BAC_CONTROL_DEST) { /* DNET, DLEN, DADR */
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
bacnet_dlen = tvb_get_guint8(tvb, offset);
|
||||
/* DLEN = 0 is broadcast on dest.network */
|
||||
if( bacnet_dlen == 0) {
|
||||
/* append to hf_bacnet_dlen: broadcast */
|
||||
proto_tree_add_uint_format(bacnet_tree,
|
||||
hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen,
|
||||
"Destination MAC Layer Address Length: %d indicates Broadcast on Destination Network",
|
||||
bacnet_dlen);
|
||||
offset ++;
|
||||
/* going to SNET */
|
||||
} else if (bacnet_dlen==6) {
|
||||
proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
|
||||
tvb, offset, 1, bacnet_dlen);
|
||||
offset ++;
|
||||
/* Ethernet MAC */
|
||||
proto_tree_add_item(bacnet_tree,
|
||||
hf_bacnet_dadr_eth, tvb, offset,
|
||||
bacnet_dlen, FALSE);
|
||||
offset += bacnet_dlen;
|
||||
} else if (bacnet_dlen<7) {
|
||||
proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
|
||||
tvb, offset, 1, bacnet_dlen);
|
||||
offset ++;
|
||||
/* Other MAC formats should be included here */
|
||||
proto_tree_add_item(bacnet_tree,
|
||||
hf_bacnet_dadr_tmp, tvb, offset,
|
||||
bacnet_dlen, FALSE);
|
||||
offset += bacnet_dlen;
|
||||
} else {
|
||||
proto_tree_add_uint_format(bacnet_tree,
|
||||
hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen,
|
||||
"Destination MAC Layer Address Length: %d invalid!",
|
||||
bacnet_dlen);
|
||||
}
|
||||
}
|
||||
if (bacnet_control & BAC_CONTROL_SRC) { /* SNET, SLEN, SADR */
|
||||
/* SNET */
|
||||
proto_tree_add_uint(bacnet_tree, hf_bacnet_snet,
|
||||
tvb, offset, 2, tvb_get_ntohs(tvb, offset));
|
||||
offset += 2;
|
||||
bacnet_slen = tvb_get_guint8(tvb, offset);
|
||||
if( bacnet_slen == 0) { /* SLEN = 0 invalid */
|
||||
proto_tree_add_uint_format(bacnet_tree,
|
||||
hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
|
||||
"Source MAC Layer Address Length: %d invalid!",
|
||||
bacnet_slen);
|
||||
offset ++;
|
||||
} else if (bacnet_slen==6) {
|
||||
/* SLEN */
|
||||
proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
|
||||
tvb, offset, 1, bacnet_slen);
|
||||
offset ++;
|
||||
/* Ethernet MAC */
|
||||
proto_tree_add_item(bacnet_tree,
|
||||
hf_bacnet_sadr_eth, tvb, offset,
|
||||
bacnet_slen, FALSE);
|
||||
offset += bacnet_slen;
|
||||
} else if (bacnet_slen<6) { /* LON,ARCNET,MS/TP MAC */
|
||||
/* SLEN */
|
||||
proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
|
||||
tvb, offset, 1, bacnet_slen);
|
||||
offset ++;
|
||||
/* Other MAC formats should be included here */
|
||||
proto_tree_add_item(bacnet_tree,
|
||||
hf_bacnet_sadr_tmp, tvb, offset,
|
||||
bacnet_slen, FALSE);
|
||||
offset += bacnet_slen;
|
||||
} else {
|
||||
proto_tree_add_uint_format(bacnet_tree,
|
||||
hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
|
||||
"Source MAC Layer Address Length: %d invalid!",
|
||||
bacnet_slen);
|
||||
offset ++;
|
||||
}
|
||||
}
|
||||
if (bacnet_control & BAC_CONTROL_DEST) { /* Hopcount */
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_hopc,
|
||||
tvb, offset, 1, FALSE);
|
||||
offset ++;
|
||||
}
|
||||
/* Network Layer Message Type */
|
||||
if (bacnet_control & BAC_CONTROL_NET) {
|
||||
bacnet_mesgtyp = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_uint_format(bacnet_tree,
|
||||
hf_bacnet_mesgtyp, tvb, offset, 1, bacnet_mesgtyp,
|
||||
"Network Layer Message Type: %02x (%s)", bacnet_mesgtyp,
|
||||
bacnet_mesgtyp_name(bacnet_mesgtyp));
|
||||
offset ++;
|
||||
}
|
||||
/* Vendor ID
|
||||
* The standard says: "If Bit 7 of the control octet is 1 and
|
||||
* the Message Type field contains a value in the range
|
||||
* X'80' - X'FF', then a Vendor ID field shall be present (...)."
|
||||
* We should not go any further in dissecting the packet if it's
|
||||
* not present, but we don't know about that: No length field...
|
||||
*/
|
||||
if ((bacnet_mesgtyp > 0x7f) && (bacnet_control == BAC_CONTROL_NET)) {
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_vendor,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
/* attention: doesnt work here because of if(tree) */
|
||||
dissect_data(tvb, offset, pinfo, tree);
|
||||
}
|
||||
/* Performance Index (in I-Could-Be-Router-To-Network) */
|
||||
if (bacnet_mesgtyp == BAC_NET_ICB_R) {
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_perf,
|
||||
tvb, offset, 1, FALSE);
|
||||
offset ++;
|
||||
}
|
||||
/* Reason, DNET (in Reject-Message-To-Network) */
|
||||
if (bacnet_mesgtyp == BAC_NET_REJ) {
|
||||
bacnet_rejectreason = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_uint_format(bacnet_tree,
|
||||
hf_bacnet_rejectreason,
|
||||
tvb, offset, 1,
|
||||
bacnet_rejectreason, "Rejection Reason: %d (%s)",
|
||||
bacnet_rejectreason,
|
||||
bacnet_rejectreason_name(bacnet_rejectreason));
|
||||
offset ++;
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
}
|
||||
/* N*DNET (in Router-Busy-To-Network,Router-Available-To-Network) */
|
||||
if ((bacnet_mesgtyp == BAC_NET_R_BUSY) ||
|
||||
(bacnet_mesgtyp == BAC_NET_R_AVA) || (bacnet_mesgtyp == BAC_NET_IAM_R) ) {
|
||||
while(tvb_reported_length_remaining(tvb, offset) > 1 ) {
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
/* Initialize-Routing-Table */
|
||||
if ( (bacnet_mesgtyp == BAC_NET_INIT_RTAB) ||
|
||||
(bacnet_mesgtyp == BAC_NET_INIT_RTAB_ACK) ) {
|
||||
bacnet_rportnum = tvb_get_guint8(tvb, offset);
|
||||
/* number of ports */
|
||||
proto_tree_add_uint(bacnet_tree, hf_bacnet_rportnum,
|
||||
tvb, offset, 1, bacnet_rportnum);
|
||||
offset ++;
|
||||
for(i=0; i>bacnet_rportnum; i++) {
|
||||
/* Connected DNET */
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
/* Port ID */
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_portid,
|
||||
tvb, offset, 1, FALSE);
|
||||
offset ++;
|
||||
/* Port Info Length */
|
||||
bacnet_pinfolen = tvb_get_guint8(tvb, offset);
|
||||
proto_tree_add_uint(bacnet_tree, hf_bacnet_pinfolen,
|
||||
tvb, offset, 1, bacnet_pinfolen);
|
||||
offset ++;
|
||||
for(j=0; j>bacnet_pinfolen; j++){
|
||||
/* Port Info */
|
||||
proto_tree_add_item(bacnet_tree, hf_bacnet_pinfo,
|
||||
tvb, offset, 1, FALSE);
|
||||
offset ++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
proto_item_set_len(ti, offset);
|
||||
}
|
||||
|
||||
/* dissect BACnet APDU
|
||||
*/
|
||||
next_tvb = tvb_new_subset(tvb,offset,-1,-1);
|
||||
/* Code from Guy Harris */
|
||||
if (!dissector_try_port(bacnet_dissector_table,
|
||||
bacnet_control_net, next_tvb, pinfo, tree)) {
|
||||
/* Unknown function - dissect the payload as data */
|
||||
dissect_data(next_tvb, 0, pinfo, tree);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
proto_register_bacnet(void)
|
||||
{
|
||||
static hf_register_info hf[] = {
|
||||
{ &hf_bacnet_version,
|
||||
{ "Version", "bacnet.version",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"BACnet Version" }
|
||||
},
|
||||
{ &hf_bacnet_control,
|
||||
{ "Control", "bacnet.control",
|
||||
FT_UINT8, BASE_HEX, NULL, 0xff,
|
||||
"BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_net,
|
||||
{ "NSDU contains",
|
||||
"bacnet.control_net",
|
||||
FT_BOOLEAN, 8, TFS(&control_net_set_high),
|
||||
BAC_CONTROL_NET, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_res1,
|
||||
{ "Reserved",
|
||||
"bacnet.control_res1",
|
||||
FT_BOOLEAN, 8, TFS(&control_res_high),
|
||||
BAC_CONTROL_RES1, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_dest,
|
||||
{ "Destination Specifier",
|
||||
"bacnet.control_dest",
|
||||
FT_BOOLEAN, 8, TFS(&control_dest_high),
|
||||
BAC_CONTROL_DEST, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_res2,
|
||||
{ "Reserved",
|
||||
"bacnet.control_res2",
|
||||
FT_BOOLEAN, 8, TFS(&control_res_high),
|
||||
BAC_CONTROL_RES2, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_src,
|
||||
{ "Source specifier",
|
||||
"bacnet.control_src",
|
||||
FT_BOOLEAN, 8, TFS(&control_src_high),
|
||||
BAC_CONTROL_SRC, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_expect,
|
||||
{ "Expecting Reply",
|
||||
"bacnet.control_expect",
|
||||
FT_BOOLEAN, 8, TFS(&control_expect_high),
|
||||
BAC_CONTROL_EXPECT, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_prio_high,
|
||||
{ "Priority",
|
||||
"bacnet.control_prio_high",
|
||||
FT_BOOLEAN, 8, TFS(&control_prio_high_high),
|
||||
BAC_CONTROL_PRIO_HIGH, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_control_prio_low,
|
||||
{ "Priority",
|
||||
"bacnet.control_prio_low",
|
||||
FT_BOOLEAN, 8, TFS(&control_prio_low_high),
|
||||
BAC_CONTROL_PRIO_LOW, "BACnet Control" }
|
||||
},
|
||||
{ &hf_bacnet_dnet,
|
||||
{ "Destination Network Address", "bacnet.dnet",
|
||||
FT_UINT16, BASE_HEX, NULL, 0,
|
||||
"Destination Network Address" }
|
||||
},
|
||||
{ &hf_bacnet_dlen,
|
||||
{ "Destination MAC Layer Address Length", "bacnet.dlen",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Destination MAC Layer Address Length" }
|
||||
},
|
||||
{ &hf_bacnet_dadr_eth,
|
||||
{ "Destination ISO 8802-3 MAC Address", "bacnet.dadr_eth",
|
||||
FT_ETHER, BASE_HEX, NULL, 0,
|
||||
"Destination ISO 8802-3 MAC Address" }
|
||||
},
|
||||
{ &hf_bacnet_dadr_tmp,
|
||||
{ "Unknown Destination MAC", "bacnet.dadr_tmp",
|
||||
FT_BYTES, BASE_HEX, NULL, 0,
|
||||
"Unknown Destination MAC" }
|
||||
},
|
||||
{ &hf_bacnet_snet,
|
||||
{ "Source Network Address", "bacnet.snet",
|
||||
FT_UINT16, BASE_HEX, NULL, 0,
|
||||
"Source Network Address" }
|
||||
},
|
||||
{ &hf_bacnet_slen,
|
||||
{ "Source MAC Layer Address Length", "bacnet.slen",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Source MAC Layer Address Length" }
|
||||
},
|
||||
{ &hf_bacnet_sadr_eth,
|
||||
{ "SADR", "bacnet.sadr_eth",
|
||||
FT_ETHER, BASE_HEX, NULL, 0,
|
||||
"Source ISO 8802-3 MAC Address" }
|
||||
},
|
||||
{ &hf_bacnet_sadr_tmp,
|
||||
{ "Unknown Source MAC", "bacnet.sadr_tmp",
|
||||
FT_BYTES, BASE_HEX, NULL, 0,
|
||||
"Unknown Source MAC" }
|
||||
},
|
||||
{ &hf_bacnet_hopc,
|
||||
{ "Hop Count", "bacnet.hopc",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Hop Count" }
|
||||
},
|
||||
{ &hf_bacnet_mesgtyp,
|
||||
{ "Message Type", "bacnet.mesgtyp",
|
||||
FT_UINT8, BASE_HEX, NULL, 0,
|
||||
"Message Type" }
|
||||
},
|
||||
{ &hf_bacnet_vendor,
|
||||
{ "Vendor ID", "bacnet.vendor",
|
||||
FT_UINT16, BASE_HEX, NULL, 0,
|
||||
"Vendor ID" }
|
||||
},
|
||||
{ &hf_bacnet_perf,
|
||||
{ "Performance Index", "bacnet.perf",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Performance Index" }
|
||||
},
|
||||
{ &hf_bacnet_rejectreason,
|
||||
{ "Reject Reason", "bacnet.rejectreason",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Reject Reason" }
|
||||
},
|
||||
{ &hf_bacnet_rportnum,
|
||||
{ "Number of Port Mappings", "bacnet.rportnum",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Number of Port Mappings" }
|
||||
},
|
||||
{ &hf_bacnet_pinfolen,
|
||||
{ "Port Info Length", "bacnet.pinfolen",
|
||||
FT_UINT8, BASE_DEC, NULL, 0,
|
||||
"Port Info Length" }
|
||||
},
|
||||
{ &hf_bacnet_portid,
|
||||
{ "Port ID", "bacnet.portid",
|
||||
FT_UINT8, BASE_HEX, NULL, 0,
|
||||
"Port ID" }
|
||||
},
|
||||
{ &hf_bacnet_pinfo,
|
||||
{ "Port Info", "bacnet.pinfo",
|
||||
FT_UINT8, BASE_HEX, NULL, 0,
|
||||
"Port Info" }
|
||||
},
|
||||
};
|
||||
|
||||
static gint *ett[] = {
|
||||
&ett_bacnet,
|
||||
&ett_bacnet_control,
|
||||
};
|
||||
|
||||
proto_bacnet = proto_register_protocol("Building Automation and Control Network NPDU",
|
||||
"BACnet", "bacnet");
|
||||
|
||||
proto_register_field_array(proto_bacnet, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
|
||||
register_dissector("bacnet", dissect_bacnet, proto_bacnet);
|
||||
bacnet_dissector_table = register_dissector_table("bacnet_control_net");
|
||||
}
|
||||
|
||||
void
|
||||
proto_reg_handoff_bacnet(void)
|
||||
{
|
||||
dissector_add("bvlc.function", 0x04, dissect_bacnet, proto_bacnet);
|
||||
dissector_add("bvlc.function", 0x09, dissect_bacnet, proto_bacnet);
|
||||
dissector_add("bvlc.function", 0x0a, dissect_bacnet, proto_bacnet);
|
||||
dissector_add("bvlc.function", 0x0b, dissect_bacnet, proto_bacnet);
|
||||
}
|
|
@ -0,0 +1,415 @@
|
|||
/* packet-bvlc.c
|
||||
* Routines for BACnet/IP (BVLL, BVLC) dissection
|
||||
* Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
|
||||
*
|
||||
* $Id: packet-bvlc.c,v 1.1 2001/03/31 10:13:11 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@unicom.net>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* Copied from README.developer,v 1.23
|
||||
*
|
||||
* 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 "prefs.h"
|
||||
#include "strutil.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef NEED_SNPRINTF_H
|
||||
# include "snprintf.h"
|
||||
#endif
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
static int proto_bvlc = -1;
|
||||
static int hf_bvlc_type = -1;
|
||||
static int hf_bvlc_function = -1;
|
||||
static int hf_bvlc_length = -1;
|
||||
static int hf_bvlc_result = -1;
|
||||
static int hf_bvlc_bdt_ip = -1;
|
||||
static int hf_bvlc_bdt_mask = -1;
|
||||
static int hf_bvlc_bdt_port = -1;
|
||||
static int hf_bvlc_reg_ttl = -1;
|
||||
static int hf_bvlc_fdt_ip = -1;
|
||||
static int hf_bvlc_fdt_port = -1;
|
||||
static int hf_bvlc_fdt_ttl = -1;
|
||||
static int hf_bvlc_fdt_timeout = -1;
|
||||
static int hf_bvlc_fwd_ip = -1;
|
||||
static int hf_bvlc_fwd_port = -1;
|
||||
|
||||
|
||||
|
||||
static dissector_table_t bvlc_dissector_table;
|
||||
|
||||
static const char*
|
||||
bvlc_function_name (guint8 bvlc_function){
|
||||
static const char *type_names[] = {
|
||||
"BVLC-Result",
|
||||
"Write-Broadcast-Distribution-Table",
|
||||
"Read-Broadcast-Distribution-Table",
|
||||
"Read-Broadcast-Distribution-Table-Ack",
|
||||
"Forwarded-NPDU",
|
||||
"Register-Foreign-Device",
|
||||
"Read-Foreign-Device-Table",
|
||||
"Read-Foreign-Device-Table-Ack",
|
||||
"Delete-Foreign-Device-Table-Entry",
|
||||
"Distribute-Broadcast-To-Network",
|
||||
"Original-Unicast-NPDU",
|
||||
"Original-Broadcast-NPDU"
|
||||
};
|
||||
return (bvlc_function > 0xb)? "unknown" : type_names[bvlc_function];
|
||||
}
|
||||
|
||||
static const char*
|
||||
bvlc_result_name (guint16 bvlc_result){
|
||||
static const char *result_names[] = {
|
||||
"Successful completion",
|
||||
"Write-Broadcast-Distribution-Table NAK",
|
||||
"Read-Broadcast-Distribution-Table NAK",
|
||||
"Register-Foreign-Device NAK",
|
||||
"Read-Foreign-Device-Table NAK",
|
||||
"Delete-Foreign-Device-Table-Entry NAK",
|
||||
"Distribute-Broadcast-To-Network NAK"
|
||||
};
|
||||
return (bvlc_result > 0x0060)? "unknown" : result_names[bvlc_result];
|
||||
}
|
||||
|
||||
static gint ett_bvlc = -1;
|
||||
static gint ett_bdt = -1;
|
||||
static gint ett_fdt = -1;
|
||||
|
||||
static void
|
||||
dissect_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
||||
{
|
||||
|
||||
proto_item *ti;
|
||||
proto_item *ti_bdt;
|
||||
proto_item *ti_fdt;
|
||||
proto_tree *bvlc_tree;
|
||||
proto_tree *bdt_tree; /* Broadcast Distribution Table */
|
||||
proto_tree *fdt_tree; /* Foreign Device Table */
|
||||
|
||||
gint offset;
|
||||
guint8 bvlc_type;
|
||||
guint8 bvlc_function;
|
||||
guint16 bvlc_length;
|
||||
guint16 packet_length;
|
||||
guint8 npdu_length;
|
||||
guint16 bvlc_result;
|
||||
tvbuff_t *next_tvb;
|
||||
|
||||
pinfo->current_proto = "BACnet virtual link control";
|
||||
|
||||
if (check_col(pinfo->fd, COL_PROTOCOL))
|
||||
col_set_str(pinfo->fd, COL_PROTOCOL, "BVLC");
|
||||
|
||||
if (check_col(pinfo->fd, COL_INFO))
|
||||
col_set_str(pinfo->fd, COL_INFO, "BACnet Virtual Link Control");
|
||||
|
||||
offset = 0;
|
||||
|
||||
bvlc_type = tvb_get_guint8(tvb, offset);
|
||||
bvlc_function = tvb_get_guint8(tvb, offset+1);
|
||||
packet_length = tvb_get_ntohs(tvb, offset+2);
|
||||
if (bvlc_function > 0x08) {
|
||||
/* We have a constant header length of BVLC of 4 in every
|
||||
* BVLC-packet forewarding an NPDU. Beware: Changes in the
|
||||
* BACnet-IP-standard may break this.
|
||||
* At the moment, no functions above 0x0b
|
||||
* exist (Addendum 135a to ANSI/ASHRAE 135-1995 - BACnet)
|
||||
*/
|
||||
bvlc_length = 4;
|
||||
} else if(bvlc_function == 0x04) {
|
||||
/* 4 Bytes + 6 Bytes for B/IP Address of Originating Device */
|
||||
bvlc_length = 10;
|
||||
} else {
|
||||
/* BVLC-packets with function below 0x09 contain
|
||||
* routing-level data (e.g. Broadcast Distribution)
|
||||
* but no NPDU for BACnet, so bvlc_length goes up to the end
|
||||
* of the captured frame.
|
||||
*/
|
||||
bvlc_length = packet_length;
|
||||
}
|
||||
|
||||
if (tree) {
|
||||
ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0,
|
||||
bvlc_length, FALSE);
|
||||
bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
|
||||
proto_tree_add_uint_format(bvlc_tree, hf_bvlc_type, tvb, offset, 1,
|
||||
bvlc_type,"Type: 0x%x (Version %s)",bvlc_type,
|
||||
(bvlc_type == 0x81)?"BACnet/IP (Annex J)":"unknown");
|
||||
offset ++;
|
||||
proto_tree_add_uint_format(bvlc_tree, hf_bvlc_function, tvb,
|
||||
offset, 1, bvlc_function,"Function: 0x%02x (%s)",
|
||||
bvlc_function, bvlc_function_name(bvlc_function));
|
||||
offset ++;
|
||||
proto_tree_add_uint_format(bvlc_tree, hf_bvlc_length, tvb, offset,
|
||||
2, bvlc_length, "BVLC-Length: %d of %d bytes BACnet packet length",
|
||||
bvlc_length, packet_length);
|
||||
offset += 2;
|
||||
switch (bvlc_function) {
|
||||
case 0x00: /* BVLC-Result */
|
||||
bvlc_result = tvb_get_ntohs(tvb, offset);
|
||||
/* I dont know why the result code is encoded in 4 nibbles,
|
||||
* but only using one: 0x00r0. Shifting left 4 bits.
|
||||
*/
|
||||
/* We should bitmask the result correctly when we have a
|
||||
* packet to dissect, see README.developer, 1.6.2, FID */
|
||||
proto_tree_add_uint_format(bvlc_tree, hf_bvlc_result, tvb,
|
||||
offset, 2, bvlc_result,"Result: 0x%04x (%s)",
|
||||
bvlc_result, bvlc_result_name(bvlc_result << 4));
|
||||
offset += 2;
|
||||
break;
|
||||
case 0x01: /* Write-Broadcast-Distribution-Table */
|
||||
case 0x03: /* Read-Broadcast-Distribution-Table-Ack */
|
||||
/* List of BDT Entries: N*10-octet */
|
||||
ti_bdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
|
||||
offset, bvlc_length-4, FALSE);
|
||||
bdt_tree = proto_item_add_subtree(ti_bdt, ett_bdt);
|
||||
/* List of BDT Entries: N*10-octet */
|
||||
while ((bvlc_length - offset) > 9) {
|
||||
proto_tree_add_item(bdt_tree, hf_bvlc_bdt_ip,
|
||||
tvb, offset, 4, FALSE);
|
||||
offset += 4;
|
||||
proto_tree_add_item(bdt_tree, hf_bvlc_bdt_port,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
proto_tree_add_item(bdt_tree,
|
||||
hf_bvlc_bdt_mask, tvb, offset, 4,
|
||||
FALSE);
|
||||
offset += 4;
|
||||
}
|
||||
/* We check this if we get a BDT-packet somewhere */
|
||||
break;
|
||||
case 0x02: /* Read-Broadcast-Distribution-Table */
|
||||
/* nothing to do here */
|
||||
break;
|
||||
case 0x05: /* Register-Foreign-Device */
|
||||
/* Time-to-Live 2-octets T, Time-to-Live T, in seconds */
|
||||
proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
break;
|
||||
case 0x06: /* Read-Foreign-Device-Table */
|
||||
/* nothing to do here */
|
||||
break;
|
||||
case 0x07: /* Read-Foreign-Device-Table-Ack */
|
||||
/* List of FDT Entries: N*10-octet */
|
||||
/* N indicates the number of entries in the FDT whose
|
||||
* contents are being returned. Each returned entry
|
||||
* consists of the 6-octet B/IP address of the registrant;
|
||||
* the 2-octet Time-to-Live value supplied at the time of
|
||||
* registration; and a 2-octet value representing the
|
||||
* number of seconds remaining before the BBMD will purge
|
||||
* the registrant's FDT entry if no re-registration occurs.
|
||||
*/
|
||||
ti_fdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
|
||||
offset, bvlc_length -4, FALSE);
|
||||
fdt_tree = proto_item_add_subtree(ti_fdt, ett_fdt);
|
||||
/* List of FDT Entries: N*10-octet */
|
||||
while ((bvlc_length - offset) > 9) {
|
||||
proto_tree_add_item(fdt_tree, hf_bvlc_fdt_ip,
|
||||
tvb, offset, 4, FALSE);
|
||||
offset += 4;
|
||||
proto_tree_add_item(fdt_tree, hf_bvlc_fdt_port,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
proto_tree_add_item(fdt_tree,
|
||||
hf_bvlc_fdt_ttl, tvb, offset, 2,
|
||||
FALSE);
|
||||
offset += 2;
|
||||
proto_tree_add_item(fdt_tree,
|
||||
hf_bvlc_fdt_timeout, tvb, offset, 2,
|
||||
FALSE);
|
||||
offset += 2;
|
||||
}
|
||||
/* We check this if we get a FDT-packet somewhere */
|
||||
break;
|
||||
case 0x08: /* Delete-Foreign-Device-Table-Entry */
|
||||
/* FDT Entry: 6-octets */
|
||||
proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ip,
|
||||
tvb, offset, 4, FALSE);
|
||||
offset += 4;
|
||||
proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
break;
|
||||
/* We check this if we get a FDT-packet somewhere */
|
||||
case 0x04: /* Forwarded-NPDU
|
||||
* Why is this 0x04? It would have been a better
|
||||
* idea to append all forewarded NPDUs at the
|
||||
* end of the function table in the B/IP-standard!
|
||||
*/
|
||||
/* proto_tree_add_bytes_format(); */
|
||||
proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_ip,
|
||||
tvb, offset, 4, FALSE);
|
||||
offset += 4;
|
||||
proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_port,
|
||||
tvb, offset, 2, FALSE);
|
||||
offset += 2;
|
||||
default:/* Distribute-Broadcast-To-Network
|
||||
* Original-Unicast-NPDU
|
||||
* Original-Broadcast-NPDU
|
||||
* Going to the next dissector...
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* Ok, no routing information BVLC packet. Dissect as
|
||||
* BACnet NPDU
|
||||
*/
|
||||
npdu_length = packet_length - bvlc_length;
|
||||
next_tvb = tvb_new_subset(tvb,bvlc_length,-1,npdu_length);
|
||||
/* Code from Guy Harris */
|
||||
if (!dissector_try_port(bvlc_dissector_table,
|
||||
bvlc_function, next_tvb, pinfo, tree)) {
|
||||
/* Unknown function - dissect the paylod as data */
|
||||
dissect_data(next_tvb, 0, pinfo, tree);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
proto_register_bvlc(void)
|
||||
{
|
||||
static hf_register_info hf[] = {
|
||||
{ &hf_bvlc_type,
|
||||
{ "Type", "bvlc.type",
|
||||
FT_UINT8, BASE_HEX, NULL, 0,
|
||||
"Type" }
|
||||
},
|
||||
{ &hf_bvlc_function,
|
||||
{ "Function", "bvlc.function",
|
||||
FT_UINT8, BASE_HEX, NULL, 0,
|
||||
"BLVC Function" }
|
||||
},
|
||||
{ &hf_bvlc_length,
|
||||
{ "Length", "bvlc.length",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"Length of BVLC" }
|
||||
},
|
||||
/* We should bitmask the result correctly when we have a
|
||||
* packet to dissect */
|
||||
{ &hf_bvlc_result,
|
||||
{ "Result", "bvlc.result",
|
||||
FT_UINT16, BASE_HEX, NULL, 0xffff,
|
||||
"Result Code" }
|
||||
},
|
||||
{ &hf_bvlc_bdt_ip,
|
||||
{ "IP", "bvlc.bdt_ip",
|
||||
FT_IPv4, BASE_NONE, NULL, 0,
|
||||
"BDT IP" }
|
||||
},
|
||||
{ &hf_bvlc_bdt_port,
|
||||
{ "Port", "bvlc.bdt_port",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"BDT Port" }
|
||||
},
|
||||
{ &hf_bvlc_bdt_mask,
|
||||
{ "Mask", "bvlc.bdt_mask",
|
||||
FT_BYTES, BASE_HEX, NULL, 0,
|
||||
"BDT Broadcast Distribution Mask" }
|
||||
},
|
||||
{ &hf_bvlc_reg_ttl,
|
||||
{ "TTL", "bvlc.reg_ttl",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"Foreign Device Time To Live" }
|
||||
},
|
||||
{ &hf_bvlc_fdt_ip,
|
||||
{ "IP", "bvlc.fdt_ip",
|
||||
FT_IPv4, BASE_NONE, NULL, 0,
|
||||
"FDT IP" }
|
||||
},
|
||||
{ &hf_bvlc_fdt_port,
|
||||
{ "Port", "bvlc.fdt_port",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"FDT Port" }
|
||||
},
|
||||
{ &hf_bvlc_fdt_ttl,
|
||||
{ "TTL", "bvlc.fdt_ttl",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"Foreign Device Time To Live" }
|
||||
},
|
||||
{ &hf_bvlc_fdt_timeout,
|
||||
{ "Timeout", "bvlc.fdt_timeout",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"Foreign Device Timeout (seconds)" }
|
||||
},
|
||||
{ &hf_bvlc_fwd_ip,
|
||||
{ "IP", "bvlc.fwd_ip",
|
||||
FT_IPv4, BASE_NONE, NULL, 0,
|
||||
"FWD IP" }
|
||||
},
|
||||
{ &hf_bvlc_fwd_port,
|
||||
{ "Port", "bvlc.fwd_port",
|
||||
FT_UINT16, BASE_DEC, NULL, 0,
|
||||
"FWD Port" }
|
||||
},
|
||||
};
|
||||
|
||||
static gint *ett[] = {
|
||||
&ett_bvlc,
|
||||
&ett_bdt,
|
||||
&ett_fdt,
|
||||
};
|
||||
|
||||
proto_bvlc = proto_register_protocol("BACnet Virtual Link Control",
|
||||
"BVLC", "bvlc");
|
||||
|
||||
proto_register_field_array(proto_bvlc, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
|
||||
register_dissector("bvlc", dissect_bvlc, proto_bvlc);
|
||||
|
||||
bvlc_dissector_table = register_dissector_table("bvlc.function");
|
||||
}
|
||||
|
||||
void
|
||||
proto_reg_handoff_bvlc(void)
|
||||
{
|
||||
dissector_add("udp.port", 0xBAC0, dissect_bvlc, proto_bvlc); /* added proto_bvlc */
|
||||
}
|
||||
/* Taken from add-135a (BACnet-IP-standard paper):
|
||||
*
|
||||
* The default UDP port for both directed messages and broadcasts shall
|
||||
* be X'BAC0' and all B/IP devices shall support it. In some cases,
|
||||
* e.g., a situation where it is desirable for two groups of BACnet devices
|
||||
* to coexist independently on the same IP subnet, the UDP port may be
|
||||
* configured locally to a different value without it being considered
|
||||
* a violation of this protocol.
|
||||
*
|
||||
* This dissector does not analyse UDP packets other than on port 0xBAC0.
|
||||
* If you changed your BACnet port locally, use the ethereal feature
|
||||
* "Decode As".
|
||||
*/
|
||||
|
27
randpkt.c
27
randpkt.c
|
@ -4,7 +4,7 @@
|
|||
* Creates random packet traces. Useful for debugging sniffers by testing
|
||||
* assumptions about the veracity of the data found in the packet.
|
||||
*
|
||||
* $Id: randpkt.c,v 1.9 2000/09/21 04:41:09 gram Exp $
|
||||
* $Id: randpkt.c,v 1.10 2001/03/31 10:13:11 guy Exp $
|
||||
*
|
||||
* Copyright (C) 1999 by Gilbert Ramirez <gram@xiexie.org>
|
||||
*
|
||||
|
@ -59,7 +59,8 @@ enum {
|
|||
PKT_SYSLOG,
|
||||
PKT_TCP,
|
||||
PKT_TR,
|
||||
PKT_UDP
|
||||
PKT_UDP,
|
||||
PKT_BVLC
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -194,6 +195,23 @@ guint8 pkt_udp[] = {
|
|||
0x0a, 0x01, 0x01, 0x63
|
||||
};
|
||||
|
||||
/* Ethernet+IP+UDP, indicating BVLC */
|
||||
guint8 pkt_bvlc[] = {
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
0x08, 0x00,
|
||||
|
||||
0x45, 0x00, 0x00, 0x3c,
|
||||
0xc5, 0x9e, 0x40, 0x00,
|
||||
0xff, 0x11, 0x01, 0xaa,
|
||||
0xc1, 0xff, 0x19, 0x1e,
|
||||
0xc1, 0xff, 0x19, 0xff,
|
||||
0xba, 0xc0, 0xba, 0xc0,
|
||||
0x00, 0xff, 0x2d, 0x5e,
|
||||
0x81
|
||||
};
|
||||
|
||||
/* This little data table drives the whole program */
|
||||
pkt_example examples[] = {
|
||||
{ "arp", "Address Resolution Protocol",
|
||||
|
@ -230,7 +248,10 @@ pkt_example examples[] = {
|
|||
PKT_TR, NULL, WTAP_ENCAP_TOKEN_RING, 0 },
|
||||
|
||||
{ "udp", "User Datagram Protocol",
|
||||
PKT_UDP, pkt_udp, WTAP_ENCAP_ETHERNET, array_length(pkt_udp) }
|
||||
PKT_UDP, pkt_udp, WTAP_ENCAP_ETHERNET, array_length(pkt_udp) },
|
||||
{ "bvlc", "BACnet Virtual Link Control",
|
||||
PKT_BVLC, pkt_bvlc, WTAP_ENCAP_ETHERNET, array_length(pkt_bvlc) }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue