BACNET support, from Hartmut Mueller.
authorGuy Harris <guy@alum.mit.edu>
Sat, 31 Mar 2001 10:13:13 +0000 (10:13 -0000)
committerGuy Harris <guy@alum.mit.edu>
Sat, 31 Mar 2001 10:13:13 +0000 (10:13 -0000)
svn path=/trunk/; revision=3214

AUTHORS
Makefile.am
Makefile.nmake
doc/ethereal.pod.template
packet-bacapp.c [new file with mode: 0644]
packet-bacnet.c [new file with mode: 0644]
packet-bvlc.c [new file with mode: 0644]
randpkt.c

diff --git a/AUTHORS b/AUTHORS
index 72c5f729a06ad944b53cf0c305dee20948c3d8c0..ced52acc039410d51fdf4fed036d1352f2ff2948 100644 (file)
--- a/AUTHORS
+++ b/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.
 
index 47655aa711147a03d8d571b1c2043c959d89958a..95e71b47ad0c6ea4220294d75cccd36767fc49c8 100644 (file)
@@ -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  \
index a1afbe760f74eeb239c6f9e71509c8c5f9e8d542..6f6f9ec221d585a3691bfe4e49dc0288156bd4f9 100644 (file)
@@ -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  \
index 0cf5a2d9eadb29abebb7914d1c9d8ff99b9222fa..0b02daa63e0e3b9ce1b487680d8794f4f29f06d8 100644 (file)
@@ -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.
diff --git a/packet-bacapp.c b/packet-bacapp.c
new file mode 100644 (file)
index 0000000..697349b
--- /dev/null
@@ -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);
+}
diff --git a/packet-bacnet.c b/packet-bacnet.c
new file mode 100644 (file)
index 0000000..d03f3ef
--- /dev/null
@@ -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);
+}
diff --git a/packet-bvlc.c b/packet-bvlc.c
new file mode 100644 (file)
index 0000000..5ddec07
--- /dev/null
@@ -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".
+ */
+
index 61e935edbe509d8e4f7666deae8bb41511d0e65f..855218c4e8229d7aee9f68cd07b6a125e7292565 100644 (file)
--- a/randpkt.c
+++ b/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) }
+
 };