* Routines for BACnet (NPDU) dissection
* Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
*
- * $Id: packet-bacnet.c,v 1.3 2001/05/30 07:48:23 guy Exp $
+ * $Id: packet-bacnet.c,v 1.17 2003/01/25 00:06:12 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#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 <epan/packet.h>
-#include "packet.h"
+#include "llcsaps.h"
-static dissector_table_t bacnet_dissector_table;
+static dissector_handle_t bacapp_handle;
+static dissector_handle_t data_handle;
static const char*
bacnet_mesgtyp_name (guint8 bacnet_mesgtyp){
"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"
gint offset;
guint8 bacnet_version;
guint8 bacnet_control;
- guint8 bacnet_control_net;
guint8 bacnet_dlen;
guint8 bacnet_slen;
guint8 bacnet_mesgtyp;
guint8 j;
tvbuff_t *next_tvb;
- if (check_col(pinfo->fd, COL_PROTOCOL))
- col_set_str(pinfo->fd, COL_PROTOCOL, "BACnet-NPDU");
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-NPDU");
- if (check_col(pinfo->fd, COL_INFO))
- col_set_str(pinfo->fd, COL_INFO, "Building Automation and Control Network NPDU");
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, 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;
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);
+ ti = proto_tree_add_item(tree, proto_bacnet, tvb, 0, -1, FALSE);
bacnet_tree = proto_item_add_subtree(ti, ett_bacnet);
- proto_tree_add_uint_format(bacnet_tree, hf_bacnet_version, tvb,
+ 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,
+ 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,
+ control_tree = proto_item_add_subtree(ct,
ett_bacnet_control);
- proto_tree_add_boolean(control_tree, hf_bacnet_control_net,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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 */
/* 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,
+ 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 ++;
tvb, offset, 1, bacnet_dlen);
offset ++;
/* Ethernet MAC */
- proto_tree_add_item(bacnet_tree,
- hf_bacnet_dadr_eth, tvb, offset,
+ proto_tree_add_item(bacnet_tree,
+ hf_bacnet_dadr_eth, tvb, offset,
bacnet_dlen, FALSE);
offset += bacnet_dlen;
} else if (bacnet_dlen<7) {
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,
+ 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,
+ proto_tree_add_uint_format(bacnet_tree,
+ hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen,
"Destination MAC Layer Address Length: %d invalid!",
bacnet_dlen);
}
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,
+ hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
"Source MAC Layer Address Length: %d invalid!",
bacnet_slen);
offset ++;
tvb, offset, 1, bacnet_slen);
offset ++;
/* Ethernet MAC */
- proto_tree_add_item(bacnet_tree,
- hf_bacnet_sadr_eth, tvb, offset,
+ 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 */
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,
+ 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,
+ hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
"Source MAC Layer Address Length: %d invalid!",
bacnet_slen);
offset ++;
offset ++;
}
/* Network Layer Message Type */
- if (bacnet_control & BAC_CONTROL_NET) {
+ 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,
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
+ /* 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...
tvb, offset, 2, FALSE);
offset += 2;
/* attention: doesnt work here because of if(tree) */
- dissect_data(tvb, offset, pinfo, tree);
+ call_dissector(data_handle,
+ tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
}
/* Performance Index (in I-Could-Be-Router-To-Network) */
if (bacnet_mesgtyp == BAC_NET_ICB_R) {
/* 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,
+ proto_tree_add_uint_format(bacnet_tree,
hf_bacnet_rejectreason,
- tvb, offset, 1,
+ tvb, offset, 1,
bacnet_rejectreason, "Rejection Reason: %d (%s)",
bacnet_rejectreason,
bacnet_rejectreason_name(bacnet_rejectreason));
offset += 2;
}
/* N*DNET (in Router-Busy-To-Network,Router-Available-To-Network) */
- if ((bacnet_mesgtyp == BAC_NET_R_BUSY) ||
+ 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,
}
}
/* Initialize-Routing-Table */
- if ( (bacnet_mesgtyp == BAC_NET_INIT_RTAB) ||
+ if ( (bacnet_mesgtyp == BAC_NET_INIT_RTAB) ||
(bacnet_mesgtyp == BAC_NET_INIT_RTAB_ACK) ) {
bacnet_rportnum = tvb_get_guint8(tvb, offset);
/* number of ports */
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)) {
+ if (bacnet_control & BAC_CONTROL_NET) {
/* Unknown function - dissect the payload as data */
- dissect_data(next_tvb, 0, pinfo, tree);
+ call_dissector(data_handle, next_tvb, pinfo, tree);
+ } else {
+ /* APDU - call the APDU dissector */
+ call_dissector(bacapp_handle, next_tvb, pinfo, tree);
}
}
{ &hf_bacnet_version,
{ "Version", "bacnet.version",
FT_UINT8, BASE_DEC, NULL, 0,
- "BACnet Version" }
+ "BACnet Version", HFILL }
},
{ &hf_bacnet_control,
{ "Control", "bacnet.control",
FT_UINT8, BASE_HEX, NULL, 0xff,
- "BACnet Control" }
+ "BACnet Control", HFILL }
},
{ &hf_bacnet_control_net,
- { "NSDU contains",
+ { "NSDU contains",
"bacnet.control_net",
FT_BOOLEAN, 8, TFS(&control_net_set_high),
- BAC_CONTROL_NET, "BACnet Control" }
+ BAC_CONTROL_NET, "BACnet Control", HFILL }
},
{ &hf_bacnet_control_res1,
- { "Reserved",
+ { "Reserved",
"bacnet.control_res1",
FT_BOOLEAN, 8, TFS(&control_res_high),
- BAC_CONTROL_RES1, "BACnet Control" }
+ BAC_CONTROL_RES1, "BACnet Control", HFILL }
},
{ &hf_bacnet_control_dest,
- { "Destination Specifier",
+ { "Destination Specifier",
"bacnet.control_dest",
FT_BOOLEAN, 8, TFS(&control_dest_high),
- BAC_CONTROL_DEST, "BACnet Control" }
+ BAC_CONTROL_DEST, "BACnet Control", HFILL }
},
{ &hf_bacnet_control_res2,
- { "Reserved",
+ { "Reserved",
"bacnet.control_res2",
FT_BOOLEAN, 8, TFS(&control_res_high),
- BAC_CONTROL_RES2, "BACnet Control" }
+ BAC_CONTROL_RES2, "BACnet Control", HFILL }
},
{ &hf_bacnet_control_src,
- { "Source specifier",
+ { "Source specifier",
"bacnet.control_src",
FT_BOOLEAN, 8, TFS(&control_src_high),
- BAC_CONTROL_SRC, "BACnet Control" }
+ BAC_CONTROL_SRC, "BACnet Control", HFILL }
},
{ &hf_bacnet_control_expect,
- { "Expecting Reply",
+ { "Expecting Reply",
"bacnet.control_expect",
FT_BOOLEAN, 8, TFS(&control_expect_high),
- BAC_CONTROL_EXPECT, "BACnet Control" }
+ BAC_CONTROL_EXPECT, "BACnet Control", HFILL }
},
{ &hf_bacnet_control_prio_high,
- { "Priority",
+ { "Priority",
"bacnet.control_prio_high",
FT_BOOLEAN, 8, TFS(&control_prio_high_high),
- BAC_CONTROL_PRIO_HIGH, "BACnet Control" }
+ BAC_CONTROL_PRIO_HIGH, "BACnet Control", HFILL }
},
{ &hf_bacnet_control_prio_low,
- { "Priority",
+ { "Priority",
"bacnet.control_prio_low",
FT_BOOLEAN, 8, TFS(&control_prio_low_high),
- BAC_CONTROL_PRIO_LOW, "BACnet Control" }
+ BAC_CONTROL_PRIO_LOW, "BACnet Control", HFILL }
},
{ &hf_bacnet_dnet,
{ "Destination Network Address", "bacnet.dnet",
FT_UINT16, BASE_HEX, NULL, 0,
- "Destination Network Address" }
+ "Destination Network Address", HFILL }
},
{ &hf_bacnet_dlen,
{ "Destination MAC Layer Address Length", "bacnet.dlen",
FT_UINT8, BASE_DEC, NULL, 0,
- "Destination MAC Layer Address Length" }
+ "Destination MAC Layer Address Length", HFILL }
},
{ &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" }
+ "Destination ISO 8802-3 MAC Address", HFILL }
},
{ &hf_bacnet_dadr_tmp,
{ "Unknown Destination MAC", "bacnet.dadr_tmp",
FT_BYTES, BASE_HEX, NULL, 0,
- "Unknown Destination MAC" }
+ "Unknown Destination MAC", HFILL }
},
{ &hf_bacnet_snet,
{ "Source Network Address", "bacnet.snet",
FT_UINT16, BASE_HEX, NULL, 0,
- "Source Network Address" }
+ "Source Network Address", HFILL }
},
{ &hf_bacnet_slen,
{ "Source MAC Layer Address Length", "bacnet.slen",
FT_UINT8, BASE_DEC, NULL, 0,
- "Source MAC Layer Address Length" }
+ "Source MAC Layer Address Length", HFILL }
},
{ &hf_bacnet_sadr_eth,
{ "SADR", "bacnet.sadr_eth",
FT_ETHER, BASE_HEX, NULL, 0,
- "Source ISO 8802-3 MAC Address" }
+ "Source ISO 8802-3 MAC Address", HFILL }
},
{ &hf_bacnet_sadr_tmp,
{ "Unknown Source MAC", "bacnet.sadr_tmp",
FT_BYTES, BASE_HEX, NULL, 0,
- "Unknown Source MAC" }
+ "Unknown Source MAC", HFILL }
},
{ &hf_bacnet_hopc,
{ "Hop Count", "bacnet.hopc",
FT_UINT8, BASE_DEC, NULL, 0,
- "Hop Count" }
+ "Hop Count", HFILL }
},
{ &hf_bacnet_mesgtyp,
{ "Message Type", "bacnet.mesgtyp",
FT_UINT8, BASE_HEX, NULL, 0,
- "Message Type" }
+ "Message Type", HFILL }
},
{ &hf_bacnet_vendor,
{ "Vendor ID", "bacnet.vendor",
FT_UINT16, BASE_HEX, NULL, 0,
- "Vendor ID" }
+ "Vendor ID", HFILL }
},
{ &hf_bacnet_perf,
{ "Performance Index", "bacnet.perf",
FT_UINT8, BASE_DEC, NULL, 0,
- "Performance Index" }
+ "Performance Index", HFILL }
},
{ &hf_bacnet_rejectreason,
{ "Reject Reason", "bacnet.rejectreason",
FT_UINT8, BASE_DEC, NULL, 0,
- "Reject Reason" }
+ "Reject Reason", HFILL }
},
{ &hf_bacnet_rportnum,
{ "Number of Port Mappings", "bacnet.rportnum",
FT_UINT8, BASE_DEC, NULL, 0,
- "Number of Port Mappings" }
+ "Number of Port Mappings", HFILL }
},
{ &hf_bacnet_pinfolen,
{ "Port Info Length", "bacnet.pinfolen",
FT_UINT8, BASE_DEC, NULL, 0,
- "Port Info Length" }
+ "Port Info Length", HFILL }
},
{ &hf_bacnet_portid,
{ "Port ID", "bacnet.portid",
FT_UINT8, BASE_HEX, NULL, 0,
- "Port ID" }
+ "Port ID", HFILL }
},
{ &hf_bacnet_pinfo,
{ "Port Info", "bacnet.pinfo",
FT_UINT8, BASE_HEX, NULL, 0,
- "Port Info" }
+ "Port Info", HFILL }
},
};
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);
+ dissector_handle_t bacnet_handle;
+
+ bacnet_handle = find_dissector("bacnet");
+ dissector_add("bvlc.function", 0x04, bacnet_handle);
+ dissector_add("bvlc.function", 0x09, bacnet_handle);
+ dissector_add("bvlc.function", 0x0a, bacnet_handle);
+ dissector_add("bvlc.function", 0x0b, bacnet_handle);
+ dissector_add("llc.dsap", SAP_BACNET, bacnet_handle);
+ bacapp_handle = find_dissector("bacapp");
+ data_handle = find_dissector("data");
}