aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-hartip.c
diff options
context:
space:
mode:
authorBill Meier <wmeier@newsguy.com>2012-03-18 19:51:39 +0000
committerBill Meier <wmeier@newsguy.com>2012-03-18 19:51:39 +0000
commita7041cacb0552d85d6e173a6d2e54e2bce4c73b4 (patch)
tree8da4f52633b069f2ec639996b18403b13997fb4b /epan/dissectors/packet-hartip.c
parent86daf87e186b20d056e26f84b7655b734d819b86 (diff)
From Bill Schiller: New dissector for the HART/IP protocol
I'm contributing a new dissector for the HART/IP protocol. This protocol is specified by the HART Conformance Foundation (HCF). It is a standard protocol used in the process control industry. It essential wraps the multip-drop serial HART packets in TCP or UDP packets. The standard has been approved by the HCF and has been assigned UDP/TCP port 5094 by IANA. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6961 --This line, and those below, will be ignored-- M AUTHORS M epan/CMakeLists.txt M epan/dissectors/Makefile.common AM epan/dissectors/packet-hartip.c M ui/gtk/main_menubar.c svn path=/trunk/; revision=41644
Diffstat (limited to 'epan/dissectors/packet-hartip.c')
-rw-r--r--epan/dissectors/packet-hartip.c1561
1 files changed, 1561 insertions, 0 deletions
diff --git a/epan/dissectors/packet-hartip.c b/epan/dissectors/packet-hartip.c
new file mode 100644
index 0000000000..af8e5f9e47
--- /dev/null
+++ b/epan/dissectors/packet-hartip.c
@@ -0,0 +1,1561 @@
+/* packet-hartip.c
+ * Routines for HART-IP packet dissection
+ * Copyright 2012, Bill Schiller <bill.schiller@emerson.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from packet-mbtcp.c
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/conversation.h>
+#include <epan/packet.h>
+#include <epan/tap.h>
+#include <epan/stats_tree.h>
+
+
+static dissector_handle_t hartip_handle;
+
+
+static int proto_hartip = -1;
+static int hf_hartip_hdr_version = -1;
+static int hf_hartip_hdr_message_id = -1;
+static int hf_hartip_hdr_message_type = -1;
+static int hf_hartip_hdr_status = -1;
+static int hf_hartip_hdr_transaction_id = -1;
+static int hf_hartip_hdr_msg_length = -1;
+
+static int hf_hartip_data = -1;
+static int hf_hartip_master_type = -1;
+static int hf_hartip_inactivity_close_timer = -1;
+static int hf_hartip_error_code = -1;
+
+static int hf_hartip_pt_preambles = -1;
+static int hf_hartip_pt_delimiter = -1;
+static int hf_hartip_pt_short_addr = -1;
+static int hf_hartip_pt_long_addr = -1;
+static int hf_hartip_pt_command = -1;
+static int hf_hartip_pt_length = -1;
+static int hf_hartip_pt_response_code = -1;
+static int hf_hartip_pt_device_status = -1;
+static int hf_hartip_pt_payload = -1;
+static int hf_hartip_pt_checksum = -1;
+
+static gint ett_hartip = -1;
+static gint ett_hartip_hdr = -1;
+static gint ett_hartip_body = -1;
+
+/* Command 0 response */
+static int hf_hartip_pt_rsp_expansion_code = -1;
+static int hf_hartip_pt_rsp_expanded_device_type = -1;
+static int hf_hartip_pt_rsp_req_min_preambles = -1;
+static int hf_hartip_pt_rsp_hart_protocol_major_rev = -1;
+static int hf_hartip_pt_rsp_device_rev = -1;
+static int hf_hartip_pt_rsp_software_rev = -1;
+static int hf_hartip_pt_rsp_hardware_rev_physical_signal = -1;
+static int hf_hartip_pt_rsp_flage = -1;
+static int hf_hartip_pt_rsp_device_id = -1;
+static int hf_hartip_pt_rsp_rsp_min_preambles = -1;
+static int hf_hartip_pt_rsp_max_device_variables = -1;
+static int hf_hartip_pt_rsp_configuration_change_counter = -1;
+static int hf_hartip_pt_rsp_extended_device_status = -1;
+static int hf_hartip_pt_rsp_manufacturer_Identification_code = -1;
+static int hf_hartip_pt_rsp_private_label = -1;
+static int hf_hartip_pt_rsp_device_profile = -1;
+
+/* Command 2 response */
+static int hf_hartip_pt_rsp_pv_percent_range = -1;
+
+/* Command 3 response */
+static int hf_hartip_pt_rsp_pv_loop_current = -1;
+static int hf_hartip_pt_rsp_pv_units = -1;
+static int hf_hartip_pt_rsp_pv = -1;
+static int hf_hartip_pt_rsp_sv_units = -1;
+static int hf_hartip_pt_rsp_sv = -1;
+static int hf_hartip_pt_rsp_tv_units = -1;
+static int hf_hartip_pt_rsp_tv = -1;
+static int hf_hartip_pt_rsp_qv_units = -1;
+static int hf_hartip_pt_rsp_qv = -1;
+
+/* Command 9 response */
+static int hf_hartip_pt_rsp_slot0_device_var = -1;
+static int hf_hartip_pt_rsp_slot0_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot0_units = -1;
+static int hf_hartip_pt_rsp_slot0_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot0_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot1_device_var = -1;
+static int hf_hartip_pt_rsp_slot1_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot1_units = -1;
+static int hf_hartip_pt_rsp_slot1_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot1_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot2_device_var = -1;
+static int hf_hartip_pt_rsp_slot2_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot2_units = -1;
+static int hf_hartip_pt_rsp_slot2_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot2_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot3_device_var = -1;
+static int hf_hartip_pt_rsp_slot3_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot3_units = -1;
+static int hf_hartip_pt_rsp_slot3_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot3_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot4_device_var = -1;
+static int hf_hartip_pt_rsp_slot4_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot4_units = -1;
+static int hf_hartip_pt_rsp_slot4_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot4_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot5_device_var = -1;
+static int hf_hartip_pt_rsp_slot5_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot5_units = -1;
+static int hf_hartip_pt_rsp_slot5_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot5_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot6_device_var = -1;
+static int hf_hartip_pt_rsp_slot6_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot6_units = -1;
+static int hf_hartip_pt_rsp_slot6_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot6_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot7_device_var = -1;
+static int hf_hartip_pt_rsp_slot7_device_var_classify = -1;
+static int hf_hartip_pt_rsp_slot7_units = -1;
+static int hf_hartip_pt_rsp_slot7_device_var_value = -1;
+static int hf_hartip_pt_rsp_slot7_device_var_status = -1;
+
+static int hf_hartip_pt_rsp_slot0_timestamp = -1;
+
+/* Command 13 response */
+static int hf_hartip_pt_rsp_packed_descriptor = -1;
+static int hf_hartip_pt_rsp_day = -1;
+static int hf_hartip_pt_rsp_month = -1;
+static int hf_hartip_pt_rsp_year = -1;
+
+/* response Tag */
+static int hf_hartip_pt_rsp_tag = -1;
+
+/* response Message */
+static int hf_hartip_pt_rsp_message = -1;
+
+/* Command 48 response */
+static int hf_hartip_pt_rsp_device_sp_status = -1;
+static int hf_hartip_pt_rsp_device_op_mode = -1;
+static int hf_hartip_pt_rsp_standardized_status_0 = -1;
+static int hf_hartip_pt_rsp_standardized_status_1 = -1;
+static int hf_hartip_pt_rsp_analog_channel_saturated = -1;
+static int hf_hartip_pt_rsp_standardized_status_2 = -1;
+static int hf_hartip_pt_rsp_standardized_status_3 = -1;
+static int hf_hartip_pt_rsp_analog_channel_fixed = -1;
+
+#define HARTIP_HEADER_LENGTH 8
+#define HARTIP_PORT 5094
+
+/* HARTIP header */
+typedef struct _hartip_hdr {
+ guint8 version;
+ guint8 message_type;
+ guint8 message_id;
+ guint8 status;
+ guint16 transaction_id;
+ guint16 length;
+} hartip_hdr;
+
+/* Message IDs */
+#define SESSION_INITIATE_ID 0
+#define SESSION_CLOSE_ID 1
+#define KEEP_ALIVE_ID 2
+#define PASS_THROUGH_ID 3
+
+/* Message types */
+#define REQUEST_MSG_TYPE 0
+#define RESPONSE_MSG_TYPE 1
+#define ERROR_MSG_TYPE 2
+
+
+static const value_string hartip_message_id_values[] = {
+ { SESSION_INITIATE_ID, "Session Initiate" },
+ { SESSION_CLOSE_ID, "Session Close" },
+ { KEEP_ALIVE_ID, "Keep Alive" },
+ { PASS_THROUGH_ID, "Pass Through" },
+ { 0, NULL }
+};
+
+static const value_string hartip_message_type_values[] = {
+ { REQUEST_MSG_TYPE, "Request" },
+ { RESPONSE_MSG_TYPE, "Response" },
+ { ERROR_MSG_TYPE, "Error" },
+ { 0, NULL }
+};
+
+/* Host types */
+#define SECONDARY_MASTER_TYPE 0
+#define PRIMARY_MASTER_TYPE 1
+
+static const value_string hartip_master_type_values[] = {
+ { SECONDARY_MASTER_TYPE, "Secondary Host" },
+ { PRIMARY_MASTER_TYPE, "Primary Host" },
+ { 0, NULL }
+};
+
+
+/* Error Codes */
+#define SESSION_CLOSED_ERROR 0
+#define PRIMARY_SESSION_UNAVAILABLE_ERROR 1
+#define SERVICE_UNAVAILABLE_ERROR 2
+
+static const value_string hartip_error_code_values[] = {
+ { SESSION_CLOSED_ERROR, "Session closed" },
+ { PRIMARY_SESSION_UNAVAILABLE_ERROR, "Primary session unavailable" },
+ { SERVICE_UNAVAILABLE_ERROR, "Service unavailable" },
+ { 0, NULL }
+};
+
+
+/* Handle for statistics tap. */
+static int hartip_tap = -1;
+
+/* Structure used for passing data for statistics processing. */
+typedef struct _hartip_tap_info {
+ gint8 message_type;
+ gint8 message_id;
+} hartip_tap_info;
+
+/* Names of items in statistics tree. */
+static const gchar* st_str_packets = "Total HART_IP Packets";
+static const gchar* st_str_requests = "Request Packets";
+static const gchar* st_str_responses = "Response Packets";
+static const gchar* st_str_errors = "Error Packets";
+
+/* Handles of items in statistics tree. */
+static int st_node_packets = -1;
+static int st_node_requests = -1;
+static int st_node_responses = -1;
+static int st_node_errors = -1;
+
+static void
+hartip_stats_tree_init(stats_tree* st) {
+ st_node_packets = stats_tree_create_node(st, st_str_packets, 0, TRUE);
+ st_node_requests = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
+ st_node_responses = stats_tree_create_node(st, st_str_responses, st_node_packets, TRUE);
+ st_node_errors = stats_tree_create_node(st, st_str_errors, st_node_packets, TRUE);
+}
+
+static int
+hartip_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p) {
+
+ const hartip_tap_info *tapinfo = p;
+ const gchar *message_type_node_str, *message_id_node_str;
+ int message_type_node;
+
+ switch (tapinfo->message_type) {
+ case REQUEST_MSG_TYPE:
+ message_type_node_str = st_str_requests;
+ message_type_node = st_node_requests;
+ break;
+ case RESPONSE_MSG_TYPE:
+ message_type_node_str = st_str_responses;
+ message_type_node = st_node_responses;
+ break;
+ case ERROR_MSG_TYPE:
+ message_type_node_str = st_str_errors;
+ message_type_node = st_node_errors;
+ break;
+ default:
+ return 0; /* Don't want to track invalid messages for now. */
+ }
+
+ message_id_node_str = val_to_str(tapinfo->message_id,
+ hartip_message_id_values, "Unknown message %d");
+
+ tick_stat_node(st, (guint8*)st_str_packets, 0, FALSE);
+ tick_stat_node(st, (guint8*)message_type_node_str, st_node_packets, FALSE);
+ tick_stat_node(st, (guint8*)message_id_node_str, message_type_node, FALSE);
+
+ return 1;
+}
+
+static gint
+dissect_empty_body(proto_tree *tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ proto_item *ti;
+
+ ti = proto_tree_add_item(tree, hf_hartip_data, tvb, offset, bodylen, ENC_NA);
+ if (bodylen == 0) {
+ proto_item_set_text(ti, "No data");
+ } else {
+ proto_item_set_text(ti, "Unexpected message body");
+ }
+ return bodylen;
+}
+
+static gint
+dissect_session_init(proto_tree *body_tree, tvbuff_t *tvb,
+ gint8 msg_type_val, gint offset, gint bodylen)
+{
+ proto_item *ti;
+ guint8 master_type;
+ const char *master_type_str;
+
+ msg_type_val = msg_type_val;
+ if (bodylen == 5) {
+ master_type = tvb_get_guint8(tvb, offset);
+ ti = proto_tree_add_uint(body_tree, hf_hartip_master_type, tvb, offset, 1,
+ master_type);
+ offset++;
+ master_type_str = val_to_str(master_type, hartip_master_type_values,
+ "Unknown host type %d");
+ proto_item_set_text(ti, "Host Type: %s", master_type_str);
+
+ proto_tree_add_uint(body_tree, hf_hartip_inactivity_close_timer, tvb, offset, 4,
+ tvb_get_ntohl(tvb, offset));
+ } else {
+ proto_tree_add_item(body_tree, hf_hartip_data, tvb, offset,
+ bodylen, ENC_NA);
+ }
+
+ return bodylen;
+}
+
+static gint
+dissect_error(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen == 1) {
+ proto_tree_add_uint(body_tree, hf_hartip_error_code, tvb, offset, 1,
+ tvb_get_guint8(tvb, offset));
+ } else {
+ proto_tree_add_item(body_tree, hf_hartip_data, tvb, offset,
+ bodylen, ENC_NA);
+ }
+
+ return bodylen;
+}
+
+static gint
+dissect_session_close(proto_tree *body_tree, tvbuff_t *tvb,
+ gint8 msg_type_val, gint offset, gint bodylen)
+{
+ msg_type_val = msg_type_val;
+ return dissect_empty_body(body_tree, tvb, offset, bodylen);
+}
+
+static gint
+dissect_keep_alive(proto_tree *body_tree, tvbuff_t *tvb,
+ gint8 msg_type_val, gint offset, gint bodylen)
+{
+ msg_type_val = msg_type_val;
+ return dissect_empty_body(body_tree, tvb, offset, bodylen);
+}
+
+static gint
+dissect_byte(proto_tree *tree, int hf, tvbuff_t *tvb, gint offset)
+{
+ proto_tree_add_uint(tree, hf, tvb, offset, 1, tvb_get_guint8(tvb, offset));
+ return 1;
+}
+static gint
+dissect_short(proto_tree *tree, int hf, tvbuff_t *tvb, gint offset)
+{
+ proto_tree_add_uint(tree, hf, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
+ return 2;
+}
+
+static gint
+dissect_float(proto_tree *tree, int hf, tvbuff_t *tvb, gint offset)
+{
+ proto_tree_add_item(tree, hf, tvb, offset, sizeof(gfloat), ENC_BIG_ENDIAN);
+ return 4;
+}
+
+static gint
+dissect_string(proto_tree *tree, int hf, char *name, int len, tvbuff_t *tvb,
+ gint offset)
+{
+ proto_item *ti;
+ char *str;
+
+ str = ep_alloc(256);
+
+ ti = proto_tree_add_item(tree, hf, tvb, offset, len, ENC_NA);
+ if (len < 256) {
+ (void) tvb_get_nstringz0(tvb, offset, len + 1, str);
+ proto_item_set_text(ti, "%s: %s", name, str);
+ }
+
+ return len;
+}
+
+static gint
+dissect_packAscii(proto_tree *tree, int hf, char *name, int len, tvbuff_t *tvb,
+ gint offset)
+{
+ gushort usIdx;
+ gushort usGroupCnt;
+ gushort usMaxGroups; /* Number of 4 byte groups to pack. */
+ gushort usMask;
+ gint iIndex;
+ gint i = 0;
+ proto_item *ti;
+ gushort buf[4];
+ guint8 *tmp;
+ char *str = NULL;
+
+ str = ep_alloc(256+1);
+
+ ti = proto_tree_add_item(tree, hf, tvb, offset, len, ENC_NA);
+
+ DISSECTOR_ASSERT(len < 3 * (256/4));
+ tmp = ep_alloc0(len);
+ tvb_memcpy(tvb, tmp, offset, len);
+
+ iIndex = 0;
+ usMaxGroups = (gushort)(len / 3);
+ for (usGroupCnt = 0; usGroupCnt < usMaxGroups; usGroupCnt++) {
+ /*
+ * First unpack 3 bytes into a group of 4 bytes, clearing bits 6 & 7.
+ */
+ buf[0] = (gushort)(tmp[iIndex] >> 2);
+ buf[1] = (gushort)(((tmp[iIndex] << 4) & 0x30) | (tmp[iIndex + 1] >> 4));
+ buf[2] = (gushort)(((tmp[iIndex + 1] << 2) & 0x3C) | (tmp[iIndex + 2] >> 6));
+ buf[3] = (gushort)(tmp[iIndex + 2] & 0x3F);
+ iIndex += 3;
+
+ /*
+ * Now transfer to unpacked area, setting bit 6 to complement of bit 5.
+ */
+ for (usIdx = 0; usIdx < 4; usIdx++) {
+ usMask = (gushort)(((buf[usIdx] & 0x20) << 1) ^ 0x40);
+ DISSECTOR_ASSERT(i < 256);
+ str[i++] = (gchar)(buf[usIdx] | usMask);
+ }
+ }
+ str[i] = '\0';
+ proto_item_set_text(ti, "%s: %s", name, str);
+
+ return len;
+}
+
+static gint
+dissect_timestamp(proto_tree *tree, int hf, char *name, int len, tvbuff_t *tvb,
+ gint offset)
+{
+ proto_item *ti;
+ guint32 t;
+ guint32 hrs = 0;
+ guint32 mins = 0;
+ guint32 secs = 0;
+ guint32 ms = 0;
+
+ ti = proto_tree_add_item(tree, hf, tvb, offset, len, ENC_NA);
+ t = tvb_get_ntohl(tvb, offset);
+
+ if (t > 0 ) {
+ t /= 32;
+ ms = t % 1000;
+ t /= 1000;
+ secs = t % 60;
+ t /= 60;
+ mins = t % 60;
+ hrs = (guint)(t / 60);
+ }
+
+ proto_item_set_text(ti, "%s: %02d:%02d:%02d.%03d", name, hrs, mins, secs, ms);
+ return len;
+}
+
+static gint
+dissect_cmd0(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen >= 22) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_expansion_code, tvb, offset);
+ offset += dissect_short(body_tree, hf_hartip_pt_rsp_expanded_device_type, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_req_min_preambles, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_hart_protocol_major_rev, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_device_rev, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_software_rev, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_hardware_rev_physical_signal, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_flage, tvb, offset);
+ proto_tree_add_item(body_tree, hf_hartip_pt_rsp_device_id, tvb, offset, 3, ENC_NA);
+ offset += 3;
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_rsp_min_preambles, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_max_device_variables, tvb, offset);
+ offset += dissect_short(body_tree, hf_hartip_pt_rsp_configuration_change_counter, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_extended_device_status, tvb, offset);
+ offset += dissect_short(body_tree, hf_hartip_pt_rsp_manufacturer_Identification_code, tvb, offset);
+ offset += dissect_short(body_tree, hf_hartip_pt_rsp_private_label, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_device_profile, tvb, offset);
+
+ return bodylen;
+ }
+
+ return 0;
+}
+
+static gint
+dissect_cmd1(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen >= 5) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_pv_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_pv, tvb, offset);
+ return bodylen;
+ }
+
+ return 0;
+}
+
+static gint
+dissect_cmd2(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen >= 8) {
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_pv_loop_current, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_pv_percent_range, tvb, offset);
+ return bodylen;
+ }
+
+ return 0;
+}
+
+static gint
+dissect_cmd3(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen >= 24) {
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_pv_loop_current, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_pv_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_pv, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_sv_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_sv, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_tv_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_tv, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_qv_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_qv, tvb, offset);
+
+ return bodylen;
+ }
+
+ return 0;
+}
+
+static gint
+dissect_cmd9(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen >= 14) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_extended_device_status, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot0_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot0_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot0_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot0_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot0_device_var_status, tvb, offset);
+
+ if (bodylen >= 22) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot1_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot1_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot1_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot1_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot1_device_var_status, tvb, offset);
+ }
+
+ if (bodylen >= 30) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot2_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot2_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot2_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot2_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot2_device_var_status, tvb, offset);
+ }
+
+ if (bodylen >= 38) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot3_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot3_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot3_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot3_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot3_device_var_status, tvb, offset);
+ }
+
+ if (bodylen >= 46) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot4_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot4_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot4_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot4_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot4_device_var_status, tvb, offset);
+ }
+
+ if (bodylen >= 54) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot5_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot5_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot5_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot5_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot5_device_var_status, tvb, offset);
+ }
+
+ if (bodylen >= 62) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot6_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot6_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot6_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot6_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot6_device_var_status, tvb, offset);
+ }
+
+ if (bodylen >= 70) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot7_device_var, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot7_device_var_classify, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot7_units, tvb, offset);
+ offset += dissect_float(body_tree, hf_hartip_pt_rsp_slot7_device_var_value, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_slot7_device_var_status, tvb, offset);
+ }
+
+ dissect_timestamp(body_tree, hf_hartip_pt_rsp_slot0_timestamp, "Slot0 Data TimeStamp", 4, tvb, offset);
+
+ return bodylen;
+ }
+
+ return 0;
+}
+
+static gint
+dissect_cmd13(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen >= 21) {
+ offset += dissect_packAscii(body_tree, hf_hartip_pt_rsp_tag, "Tag", 6, tvb, offset);
+ offset += dissect_packAscii(body_tree, hf_hartip_pt_rsp_packed_descriptor, "descriptor", 12, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_day, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_month, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_year, tvb, offset);
+
+ return bodylen;
+ }
+
+ return 0;
+}
+
+static gint
+dissect_cmd48(proto_tree *body_tree, tvbuff_t *tvb,
+ gint offset, gint bodylen)
+{
+ if (bodylen >= 9) {
+ proto_tree_add_item(body_tree, hf_hartip_pt_rsp_device_sp_status, tvb, offset, 5, ENC_NA);
+ offset += 5;
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_extended_device_status, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_device_op_mode, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_standardized_status_0, tvb, offset);
+
+ if (bodylen >= 14) {
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_standardized_status_1, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_analog_channel_saturated, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_standardized_status_2, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_standardized_status_3, tvb, offset);
+ offset += dissect_byte(body_tree, hf_hartip_pt_rsp_analog_channel_fixed, tvb, offset);
+ }
+
+ if (bodylen >= 24) {
+ proto_tree_add_item(body_tree, hf_hartip_pt_rsp_device_sp_status, tvb, offset, 11, ENC_NA);
+ offset += 11;
+ }
+ return bodylen;
+ }
+
+ return 0;
+}
+
+static gint
+dissect_parse_hart_cmds(proto_tree *body_tree, tvbuff_t *tvb,
+ guint8 cmd, gint offset, gint bodylen)
+{
+ if (cmd == 0)
+ return dissect_cmd0(body_tree, tvb, offset, bodylen);
+ else if (cmd == 1)
+ return dissect_cmd1(body_tree, tvb, offset, bodylen);
+ else if (cmd == 2)
+ return dissect_cmd2(body_tree, tvb, offset, bodylen);
+ else if (cmd == 3)
+ return dissect_cmd3(body_tree, tvb, offset, bodylen);
+ else if (cmd == 9)
+ return dissect_cmd9(body_tree, tvb, offset, bodylen);
+ else if ((cmd == 12) && (bodylen >= 24))
+ return dissect_packAscii(body_tree, hf_hartip_pt_rsp_message, "Message", 24, tvb, offset);
+ else if (cmd == 13)
+ return dissect_cmd13(body_tree, tvb, offset, bodylen);
+ else if ((cmd == 20) && (bodylen >= 32))
+ return dissect_string(body_tree, hf_hartip_pt_rsp_tag, "Tag", 32, tvb, offset);
+ else if (cmd == 48)
+ return dissect_cmd48(body_tree, tvb, offset, bodylen);
+
+ return 0;
+}
+
+static gint
+dissect_pass_through(proto_tree *body_tree, tvbuff_t *tvb,
+ gint8 msg_type_val, gint offset, gint bodylen)
+{
+ proto_item *ti;
+ guint8 delimiter;
+ const char *frame_type_str;
+ guint8 tmp;
+ guint8 cmd = 0;
+ gint length = bodylen;
+ gint is_short = 0;
+ gint is_rsp = 0;
+ gint num_preambles = 0;
+ gint result;
+
+ msg_type_val = msg_type_val;
+
+ /* find number of preambles */
+ while (length > num_preambles) {
+ delimiter = tvb_get_guint8(tvb, offset + num_preambles);
+ if (delimiter != 0xFF)
+ break;
+
+ num_preambles += 1;
+ }
+
+ if (num_preambles > 0) {
+ proto_tree_add_item(body_tree, hf_hartip_pt_preambles, tvb, offset,
+ num_preambles, ENC_NA);
+ offset += num_preambles;
+ length -= num_preambles;
+ }
+
+ if (length > 0) {
+ delimiter = tvb_get_guint8(tvb, offset);
+ ti = proto_tree_add_uint(body_tree, hf_hartip_pt_delimiter, tvb, offset, 1,
+ delimiter);
+ offset++;
+ length--;
+
+ if ((delimiter & 0x7) == 2) {
+ frame_type_str = "STX";
+ } else if ((delimiter & 0x7) == 6) {
+ frame_type_str = "ACK";
+ is_rsp = 1;
+ } else {
+ frame_type_str = "UNK";
+ }
+
+ if ((delimiter & 0x80) == 0) {
+ is_short = 1;
+ proto_item_set_text(ti, "Short Address, Frame Type: %s", frame_type_str);
+ } else {
+ proto_item_set_text(ti, "Frame Type: %s", frame_type_str);
+ }
+ }
+
+ if (is_short == 1) {
+ if (length > 0) {
+ tmp = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(body_tree, hf_hartip_pt_short_addr, tvb, offset, 1,
+ tmp);
+ offset++;
+ length--;
+ }
+ } else {
+ if (length > 4) {
+ proto_tree_add_item(body_tree, hf_hartip_pt_long_addr, tvb, offset,
+ 5, ENC_NA);
+ offset += 5;
+ length -= 5;
+ } else if (length > 0) {
+ proto_tree_add_item(body_tree, hf_hartip_data, tvb, offset,
+ length, ENC_NA);
+ length = 0;
+ }
+ }
+
+ if (length > 0) {
+ cmd = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(body_tree, hf_hartip_pt_command, tvb, offset, 1,
+ cmd);
+ offset++;
+ length--;
+ }
+ if (length > 0) {
+ tmp = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(body_tree, hf_hartip_pt_length, tvb, offset, 1,
+ tmp);
+ offset++;
+ length--;
+ }
+
+ if (is_rsp == 1) {
+ if (length > 0) {
+ tmp = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(body_tree, hf_hartip_pt_response_code, tvb, offset, 1,
+ tmp);
+ offset++;
+ length--;
+ }
+ if (length > 0) {
+ tmp = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(body_tree, hf_hartip_pt_device_status, tvb, offset, 1,
+ tmp);
+ offset++;
+ length--;
+ }
+ }
+
+ if (length > 1) {
+ result = dissect_parse_hart_cmds(body_tree, tvb, cmd, offset, length);
+ if (result == 0 ) {
+ proto_tree_add_item(body_tree, hf_hartip_pt_payload, tvb, offset,
+ (length - 1), ENC_NA);
+ }
+ offset += (length - 1);
+ length = 1;
+ }
+ if (length > 0) {
+ tmp = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(body_tree, hf_hartip_pt_checksum, tvb, offset, 1,
+ tmp);
+ }
+
+ return bodylen;
+}
+
+static void
+hartip_set_conversation(packet_info *pinfo)
+{
+ conversation_t *conversation = NULL;
+
+ if (!pinfo->fd->flags.visited &&
+ (pinfo->ptype == PT_UDP)) {
+ /*
+ * This function is called for a session initiate send over UDP.
+ * The session initiate is sent to the server on port HARTIP_PORT.
+ * The server then responds from a different port. All subsequent
+ * communication for the session between the client and server
+ * uses the new server port and the original client port.
+ *
+ * A new conversation is created here and this dissector is set to
+ * be used for it. This allows the packets to be dissected properly
+ * for this protocol.
+ */
+ conversation = find_conversation(pinfo->fd->num,
+ &pinfo->src, &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, 0, NO_PORT_B);
+ if( (conversation == NULL) ||
+ (conversation->dissector_handle != hartip_handle) ) {
+ conversation = conversation_new(pinfo->fd->num,
+ &pinfo->src, &pinfo->dst, pinfo->ptype,
+ pinfo->srcport, 0, NO_PORT2);
+ conversation_set_dissector(conversation, hartip_handle);
+ }
+ }
+}
+
+static void
+dissect_hartip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *hartip_tree, *hdr_tree, *body_tree;
+ proto_item *ti, *hdr_node, *body_node;
+ gint offset = 0;
+ gint bodylen;
+ gint packet_count = 0;
+ hartip_hdr hdr;
+ const char *msg_id_str, *msg_type_str;
+ hartip_tap_info *tapinfo;
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "HART_IP");
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ while (1) {
+ if (tvb_reported_length_remaining(tvb, offset) < HARTIP_HEADER_LENGTH)
+ return;
+
+ tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hartip_hdr));
+ hdr.transaction_id = g_ntohs(hdr.transaction_id);
+ hdr.length = g_ntohs(hdr.length);
+
+ msg_id_str = val_to_str(hdr.message_id, hartip_message_id_values, "Unknown message %d");
+ msg_type_str = val_to_str(hdr.message_type, hartip_message_type_values,
+ "Unknown message type %d");
+ bodylen = hdr.length - HARTIP_HEADER_LENGTH;
+
+ /* Setup statistics for tap. */
+ tapinfo = ep_alloc(sizeof(hartip_tap_info));
+ tapinfo->message_type = hdr.message_type;
+ tapinfo->message_id = hdr.message_id;
+
+ if (hdr.message_id == SESSION_INITIATE_ID) {
+ hartip_set_conversation(pinfo);
+ }
+
+ if (packet_count == 0) {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "%s %s, Sequence Number %d",
+ msg_id_str,
+ msg_type_str,
+ hdr.transaction_id);
+ }
+ else if (packet_count == 1) {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "Multiple HART_IP Messages");
+ }
+ packet_count++;
+
+ if (tree) {
+ ti = proto_tree_add_protocol_format
+ (tree, proto_hartip, tvb, offset, hdr.length,
+ "HART_IP Protocol, %s %s, Sequence Number %d",
+ msg_id_str,
+ msg_type_str,
+ hdr.transaction_id);
+ hartip_tree = proto_item_add_subtree(ti, ett_hartip);
+
+ /* add header elements. */
+ hdr_node = proto_tree_add_text(hartip_tree, tvb, offset, HARTIP_HEADER_LENGTH,
+ "HART_IP Header");
+
+
+ hdr_tree = proto_item_add_subtree(hdr_node, ett_hartip_hdr);
+
+ proto_tree_add_uint(hdr_tree, hf_hartip_hdr_version, tvb, offset++, 1,
+ hdr.version);
+ ti = proto_tree_add_uint(hdr_tree, hf_hartip_hdr_message_type, tvb, offset++, 1,
+ hdr.message_type);
+ proto_item_set_text(ti, "Message Type: %s", msg_type_str);
+ ti = proto_tree_add_uint(hdr_tree, hf_hartip_hdr_message_id, tvb, offset++, 1,
+ hdr.message_id);
+ proto_item_set_text(ti, "Message ID: %s", msg_id_str);
+ ti = proto_tree_add_uint(hdr_tree, hf_hartip_hdr_status, tvb, offset++, 1,
+ hdr.status);
+
+ proto_tree_add_uint(hdr_tree, hf_hartip_hdr_transaction_id, tvb, offset, 2,
+ hdr.transaction_id);
+ offset += 2;
+ proto_tree_add_uint(hdr_tree, hf_hartip_hdr_msg_length, tvb, offset, 2,
+ hdr.length);
+ offset += 2;
+
+ /* add body elements. */
+ if (bodylen < 0) {
+ body_node = proto_tree_add_text(hartip_tree, tvb, offset, hdr.length - HARTIP_HEADER_LENGTH,
+ "HART_IP Body - Invalid size");
+ return;
+ } else {
+ body_node = proto_tree_add_text
+ (hartip_tree, tvb, offset, bodylen, "HART_IP Body, %s, %s",
+ msg_id_str,
+ msg_type_str);
+ body_tree = proto_item_add_subtree(body_node, ett_hartip_body);
+
+ if (hdr.message_type == ERROR_MSG_TYPE) {
+ offset += dissect_error(body_tree, tvb, offset, bodylen);
+ } else {
+ /* Dissect the various HARTIP messages. */
+ switch(hdr.message_id) {
+ case SESSION_INITIATE_ID:
+ offset += dissect_session_init(body_tree, tvb, hdr.message_type, offset, bodylen);
+ break;
+ case SESSION_CLOSE_ID:
+ offset += dissect_session_close(body_tree, tvb, hdr.message_type, offset, bodylen);
+ break;
+ case KEEP_ALIVE_ID:
+ offset += dissect_keep_alive(body_tree, tvb, hdr.message_type, offset, bodylen);
+ break;
+ case PASS_THROUGH_ID:
+ offset += dissect_pass_through(body_tree, tvb, hdr.message_type, offset, bodylen);
+ break;
+ default:
+ proto_tree_add_item(body_tree, hf_hartip_data, tvb, offset,
+ bodylen, ENC_NA);
+ offset += bodylen;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ offset += hdr.length;
+ }
+
+ tap_queue_packet(hartip_tap, pinfo, tapinfo);
+ }
+}
+
+
+void
+proto_register_hartip(void)
+{
+ static hf_register_info hf[] = {
+ /* HARTIP header elements. */
+ { &hf_hartip_hdr_version,
+ { "Version", "hart_ip.version",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "HART_IP version number", HFILL }
+ },
+ { &hf_hartip_hdr_message_type,
+ { "Message Type", "hart_ip.message_type",
+ FT_UINT8, BASE_DEC, VALS(hartip_message_type_values), 0xFF,
+ "HART_IP message type", HFILL }
+ },
+ { &hf_hartip_hdr_message_id,
+ { "Message ID", "hart_ip.message_id",
+ FT_UINT8, BASE_DEC, VALS(hartip_message_id_values), 0xFF,
+ "HART_IP message id", HFILL }
+ },
+ { &hf_hartip_hdr_status,
+ { "Status", "hart_ip.status",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "HART_IP status field", HFILL }
+ },
+ { &hf_hartip_hdr_transaction_id,
+ { "Sequence Number", "hart_ip.transaction_id",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "HART_IP Sequence Number", HFILL }
+ },
+ { &hf_hartip_hdr_msg_length,
+ { "Message Length", "hart_ip.msg_length",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "HART_IP Message Length", HFILL }
+ },
+
+ /* HARTIP Body elements */
+ { &hf_hartip_data,
+ { "Message Data", "hart_ip.data",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "HART_IP Message Data", HFILL }
+ },
+ { &hf_hartip_master_type,
+ { "Host Type", "hart_ip.session_init.master_type",
+ FT_UINT8, BASE_DEC, VALS(hartip_master_type_values), 0xFF,
+ "Session Host Type", HFILL }
+ },
+ { &hf_hartip_inactivity_close_timer,
+ { "Inactivity Close Timer", "hart_ip.session_init.inactivity_close_timer",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Session Inactivity Close Timer", HFILL }
+ },
+ { &hf_hartip_error_code,
+ { "Error", "hart_ip.error.error_code",
+ FT_UINT8, BASE_DEC, VALS(hartip_error_code_values), 0xFF,
+ "Error Code", HFILL }
+ },
+
+ /* HARTIP Pass-through commads. */
+ { &hf_hartip_pt_preambles,
+ { "Preambles", "hart_ip.pt.preambles",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "Pass Through Preambles", HFILL }
+ },
+ { &hf_hartip_pt_delimiter,
+ { "Delimter", "hart_ip.pt.delimter",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Pass Through Delimiter", HFILL }
+ },
+ { &hf_hartip_pt_short_addr,
+ { "Short Address", "hart_ip.pt.short_addr",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Pass Through Short Address", HFILL }
+ },
+ { &hf_hartip_pt_long_addr,
+ { "Long Address", "hart_ip.pt.long_address",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "Pass Through Long Address", HFILL }
+ },
+ { &hf_hartip_pt_command,
+ { "Command", "hart_ip.pt.command",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Pass Through Command", HFILL }
+ },
+ { &hf_hartip_pt_length,
+ { "Length", "hart_ip.pt.length",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Pass Through Length", HFILL }
+ },
+ { &hf_hartip_pt_response_code,
+ { "Response Code", "hart_ip.pt.response_code",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Pass Through Response Code", HFILL }
+ },
+ { &hf_hartip_pt_device_status,
+ { "Device Status", "hart_ip.pt.device_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Pass Through Device Status", HFILL }
+ },
+ { &hf_hartip_pt_payload,
+ { "Payload", "hart_ip.pt.payload",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "Pass Through Payload", HFILL }
+ },
+ { &hf_hartip_pt_checksum,
+ { "Checksum", "hart_ip.pt.checksum",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Pass Through Checksum", HFILL }
+ },
+
+ /* add fields for universal commands. */
+ /* command 0 */
+ { &hf_hartip_pt_rsp_expansion_code,
+ { "Expansion Code", "hart_ip.pt.rsp.expansion_code",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_expanded_device_type,
+ { "Expanded Device Type", "hart_ip.pt.rsp.expanded_device_type",
+ FT_UINT16, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_req_min_preambles,
+ { "Minimum Number of Request Preambles", "hart_ip.pt.rsp.req_min_preambles",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_hart_protocol_major_rev,
+ { "HART Universal Revision", "hart_ip.pt.rsp.hart_univ_rev",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_device_rev,
+ { "Device Revision", "hart_ip.pt.rsp.device_rev",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_software_rev,
+ { "Device Software Revision", "hart_ip.pt.rsp.software_rev",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_hardware_rev_physical_signal,
+ { "Hardware Rev and Physical Signaling", "hart_ip.pt.rsp.hardrev_and_physical_signal",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_flage,
+ { "Flags", "hart_ip.pt.rsp.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_device_id,
+ { "Device ID", "hart_ip.pt.rsp.device_id",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_rsp_min_preambles,
+ { "Minimum Number of Response Preambles", "hart_ip.pt.rsp.rsp_min_preambles",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_max_device_variables,
+ { "Maximum Number of Device Variables", "hart_ip.pt.rsp.device_variables",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_configuration_change_counter,
+ { "Configuration Change Counter", "hart_ip.pt.rsp.configure_change",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_extended_device_status,
+ { "Extended Device Status", "hart_ip.pt.rsp.ext_device_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_manufacturer_Identification_code,
+ { "Manufacturer ID", "hart_ip.pt.rsp.manufacturer_Id",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_private_label,
+ { "Private Label", "hart_ip.pt.rsp.private_label",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_device_profile,
+ { "Device Profile", "hart_ip.pt.rsp.device_profile",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* command 2 */
+ { &hf_hartip_pt_rsp_pv_percent_range,
+ { "PV Percent Range", "hart_ip.pt.rsp.pv_percent_range",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* command 3 */
+ { &hf_hartip_pt_rsp_pv_loop_current,
+ { "PV Loop Current", "hart_ip.pt.rsp.pv_loop_current",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_pv_units,
+ { "PV Units", "hart_ip.pt.rsp.pv_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_pv,
+ { "PV", "hart_ip.pt.rsp.pv",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_sv_units,
+ { "SV Units", "hart_ip.pt.rsp.sv_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_sv,
+ { "SV", "hart_ip.pt.rsp.sv",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_tv_units,
+ { "TV Units", "hart_ip.pt.rsp.tv_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_tv,
+ { "TV", "hart_ip.pt.rsp.tv",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_qv_units,
+ { "QV Units", "hart_ip.pt.rsp.qv_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_qv,
+ { "QV", "hart_ip.pt.rsp.qv",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* command 9 */
+ { &hf_hartip_pt_rsp_slot0_device_var,
+ { "Slot0 Device Variable", "hart_ip.pt.rsp.slot0_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot0_device_var_classify,
+ { "Slot0 Device Variable Classification", "hart_ip.pt.rsp.slot0_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot0_units,
+ { "Slot0 Units", "hart_ip.pt.rsp.slot0_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot0_device_var_value,
+ { "Slot0 Device Variable Value", "hart_ip.pt.rsp.slot0_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot0_device_var_status,
+ { "Slot0 Device Variable Status", "hart_ip.pt.rsp.slot0_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot1_device_var,
+ { "Slot1 Device Variable", "hart_ip.pt.rsp.slot1_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot1_device_var_classify,
+ { "Slot1 Device Variable Classification", "hart_ip.pt.rsp.slot1_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot1_units,
+ { "Slot1 Units", "hart_ip.pt.rsp.slot1_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot1_device_var_value,
+ { "Slot1 Device Variable Value", "hart_ip.pt.rsp.slot1_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot1_device_var_status,
+ { "Slot1 Device Variable Status", "hart_ip.pt.rsp.slot1_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot2_device_var,
+ { "Slot2 Device Variable", "hart_ip.pt.rsp.slot2_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot2_device_var_classify,
+ { "Slot2 Device Variable Classification", "hart_ip.pt.rsp.slot2_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot2_units,
+ { "Slot2 Units", "hart_ip.pt.rsp.slot2_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot2_device_var_value,
+ { "Slot2 Device Variable Value", "hart_ip.pt.rsp.slot2_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot2_device_var_status,
+ { "Slot2 Device Variable Status", "hart_ip.pt.rsp.slot2_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot3_device_var,
+ { "Slot3 Device Variable", "hart_ip.pt.rsp.slot3_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot3_device_var_classify,
+ { "Slot3 Device Variable Classification", "hart_ip.pt.rsp.slot3_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot3_units,
+ { "Slot3 Units", "hart_ip.pt.rsp.slot3_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot3_device_var_value,
+ { "Slot3 Device Variable Value", "hart_ip.pt.rsp.slot3_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot3_device_var_status,
+ { "Slot3 Device Variable Status", "hart_ip.pt.rsp.slot3_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot4_device_var,
+ { "Slot4 Device Variable", "hart_ip.pt.rsp.slot4_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot4_device_var_classify,
+ { "Slot4 Device Variable Classification", "hart_ip.pt.rsp.slot4_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot4_units,
+ { "Slot4 Units", "hart_ip.pt.rsp.slot4_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot4_device_var_value,
+ { "Slot4 Device Variable Value", "hart_ip.pt.rsp.slot4_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot4_device_var_status,
+ { "Slot4 Device Variable Status", "hart_ip.pt.rsp.slot4_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot5_device_var,
+ { "Slot5 Device Variable", "hart_ip.pt.rsp.slot5_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot5_device_var_classify,
+ { "Slot5 Device Variable Classification", "hart_ip.pt.rsp.slot5_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot5_units,
+ { "Slot5 Units", "hart_ip.pt.rsp.slot5_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot5_device_var_value,
+ { "Slot5 Device Variable Value", "hart_ip.pt.rsp.slot5_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot5_device_var_status,
+ { "Slot5 Device Variable Status", "hart_ip.pt.rsp.slot5_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot6_device_var,
+ { "Slot6 Device Variable", "hart_ip.pt.rsp.slot6_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot6_device_var_classify,
+ { "Slot6 Device Variable Classification", "hart_ip.pt.rsp.slot6_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot6_units,
+ { "Slot6 Units", "hart_ip.pt.rsp.slot6_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot6_device_var_value,
+ { "Slot6 Device Variable Value", "hart_ip.pt.rsp.slot6_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot6_device_var_status,
+ { "Slot6 Device Variable Status", "hart_ip.pt.rsp.slot6_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot7_device_var,
+ { "Slot7 Device Variable", "hart_ip.pt.rsp.slot7_device_var",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot7_device_var_classify,
+ { "Slot7 Device Variable Classification", "hart_ip.pt.rsp.slot7_device_var_classify",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot7_units,
+ { "Slot7 Units", "hart_ip.pt.rsp.slot7_units",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot7_device_var_value,
+ { "Slot7 Device Variable Value", "hart_ip.pt.rsp.slot7_device_var_value",
+ FT_FLOAT, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot7_device_var_status,
+ { "Slot7 Device Variable Status", "hart_ip.pt.rsp.slot7_device_var_status",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_slot0_timestamp,
+ { "Slot0 Data TimeStamp", "hart_ip.pt.rsp.slot0_data_timestamp",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* command 13 */
+ { &hf_hartip_pt_rsp_packed_descriptor,
+ { "Descriptor", "hart_ip.pt.rsp.descriptor",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_day,
+ { "Day", "hart_ip.pt.rsp.day",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_month,
+ { "Month", "hart_ip.pt.rsp.month",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_year,
+ { "Year", "hart_ip.pt.rsp.year",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* Tag */
+ { &hf_hartip_pt_rsp_tag,
+ { "Tag", "hart_ip.pt.rsp.tag",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* Message */
+ { &hf_hartip_pt_rsp_message,
+ { "Message", "hart_ip.pt.rsp.message",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+
+ /* command 48 */
+ { &hf_hartip_pt_rsp_device_sp_status,
+ { "Device-Specific Status", "hart_ip.pt.rsp.device_sp_status",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_device_op_mode,
+ { "Device Operating Mode", "hart_ip.pt.rsp.device_op_mode",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_standardized_status_0,
+ { "Standardized Status 0", "hart_ip.pt.rsp.standardized_status_0",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_standardized_status_1,
+ { "Standardized Status 1", "hart_ip.pt.rsp.standardized_status_1",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_analog_channel_saturated,
+ { "Analog Channel Saturated", "hart_ip.pt.rsp.analog_channel_saturated",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_standardized_status_2,
+ { "Standardized Status 2", "hart_ip.pt.rsp.standardized_status_2",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_standardized_status_3,
+ { "Standardized Status 3", "hart_ip.pt.rsp.standardized_status_3",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ NULL, HFILL }
+ },
+ { &hf_hartip_pt_rsp_analog_channel_fixed,
+ { "Analog Channel Fixed", "hart_ip.pt.rsp.analog_channel_fixed",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL
+ }}
+ };
+
+ static gint *ett[] = {
+ &ett_hartip,
+ &ett_hartip_hdr,
+ &ett_hartip_body
+ };
+
+ proto_hartip = proto_register_protocol("HART_IP", "HART_IP", "hart_ip");
+ proto_register_field_array(proto_hartip, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ hartip_tap = register_tap("hart_ip");
+}
+
+void
+proto_reg_handoff_hartip(void)
+{
+ hartip_handle = create_dissector_handle(dissect_hartip, proto_hartip);
+ dissector_add_uint("udp.port", HARTIP_PORT, hartip_handle);
+ dissector_add_uint("tcp.port", HARTIP_PORT, hartip_handle);
+
+ stats_tree_register("hart_ip", "hart_ip", "HART-IP", 0,
+ hartip_stats_tree_packet, hartip_stats_tree_init, NULL );
+}