Add dissector for CP "Cooper" 2179 Protocol
authorQiaoyin Yang <qiaoyin.yang[AT]gmail.com>
Wed, 16 Jul 2014 16:50:41 +0000 (10:50 -0600)
committerAlexis La Goutte <alexis.lagoutte@gmail.com>
Thu, 4 Sep 2014 06:17:27 +0000 (06:17 +0000)
All credit for development should go Qiaoyin Yang

CP2179 protocol is a serial based protocol. The 2179 protocol is implemented with minor variations between vendors.
The RTAC implemented the 2179 client supporting a limited function codes and command codes. The RTAC doesn't support
multiple function codes in a single request and the dissector also doesn't support decoding these or corresponding responses.

Bug:10285
Change-Id: I217bf4185c52b0b183f69b3b5aa84613340d3944
Reviewed-on: https://code.wireshark.org/review/3089
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
AUTHORS
docbook/release-notes.asciidoc
epan/CMakeLists.txt
epan/dissectors/Makefile.common
epan/dissectors/packet-cp2179.c [new file with mode: 0644]
epan/dissectors/packet-rtacser.c

diff --git a/AUTHORS b/AUTHORS
index d53741e509b53b40e1f45ea3e976294888ebe227..d9add45301e3e32ddd437592a77cffddcd92a1de 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -3607,6 +3607,10 @@ Sean O. Stalley          <sean.stalley[AT]intel.com> {
        Dissector for Media Agnostic USB (MA USB)
 }
 
+Qiaoyin Yang <qiaoyin.yang[AT]gmail.com> {
+       Dissector for CP 'Cooper' 2179
+}
+
 and by:
 
 Georgi Guninski                <guninski[AT]guninski.com>
index 96627bdcbb26aadbeae918b5375177f23163be85..28912f5f5f30998e3abab9aac5951ccb528c7123 100644 (file)
@@ -124,6 +124,7 @@ corosync/totemnet
 corosync/totemsrp
 ceph
 Stateless Transport Tunneling
+CP 'Cooper' 2179
 --sort-and-group--
 
 === Updated Protocol Support
index 95cab26753240518ee7809106cb28e0c58f67874..2584b4db4e7713e409dd6a8b1ca2a10c4772f229 100644 (file)
@@ -482,6 +482,7 @@ set(DISSECTOR_SRC
        dissectors/packet-corosync-totemnet.c
        dissectors/packet-corosync-totemsrp.c
        dissectors/packet-cosine.c
+       dissectors/packet-cp2179.c
        dissectors/packet-cpfi.c
        dissectors/packet-cpha.c
        dissectors/packet-csm-encaps.c
index 7c4a7925d879136ed7876de13c2df69413f09a10..1b9cc5126ab35b763256909f86af28df64596259 100644 (file)
@@ -405,6 +405,7 @@ DISSECTOR_SRC = \
        packet-corosync-totemnet.c      \
        packet-corosync-totemsrp.c      \
        packet-cosine.c         \
+       packet-cp2179.c         \
        packet-cpfi.c           \
        packet-cpha.c           \
        packet-csm-encaps.c     \
diff --git a/epan/dissectors/packet-cp2179.c b/epan/dissectors/packet-cp2179.c
new file mode 100644 (file)
index 0000000..6bea9ab
--- /dev/null
@@ -0,0 +1,1417 @@
+/* packet-cp2179.c
+ * Routines for Communication Protocol 2179 (CP2179) Dissection
+ * By Qiaoyin Yang (qiaoyin[DOT]yang[AT]gmail.com
+ * Copyright 2014-2015,Schweitzer Engineering Laboratories
+ *
+ *
+ ************************************************************************************************
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ ************************************************************************************************
+CP2179 protocol is a serial based protocol. The 2179 protocol is implemented with minor variations between vendors.
+The RTAC implemented the 2179 client supporting a limited function codes and command codes. The RTAC doesn't support
+multiple function codes in a single request and the dissector also doesn't support decoding these or corresponding responses.
+ * Dissector Notes:
+ A brief explanation of how a request and response messages are formulated in 2179 protocol.
+ The CP2179 request messages will follow the pattern below:
+AA AA BB CC DD DD XX XX .... XX EE EE
+
+A = 16-bit address field. The Most significant 5 bit is the Client address, the 11 bits for RTU address.
+B = 8-bit Function code
+C = 8-bit Command code
+D = 16-bit Number of characters in the data field.
+X = data field
+E = 16-bit CRC
+
+AA AA BB CC DD EE EE XX XX ... XX FF FF
+
+A = 16-bit address field. The Most significant 5 bit is the Client address, the 11 bits for RTU address.
+B = 8-bit Function code
+C = 8-bit Status
+D = 8-bit Port Status
+E = 16-bit Number of characters
+X = data field
+F = 16-bit CRC
+ ************************************************************************************************/
+
+#include "config.h"
+#include <epan/packet.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/to_str.h>
+#include <epan/conversation.h>
+#include <epan/wmem/wmem.h>
+
+#include <epan/prefs.h>
+#include <epan/reassemble.h>
+#include <epan/expert.h>
+
+
+/* CP2179 function codes */
+#define BASIC_SCAN                          0x00
+#define SCAN_INCLUSIVE                      0x01
+#define SCAN_FOR_SPECIAL_CALC               0x03
+#define RETRIEVE_TIME_TAGGED_INFOR          0x04   /* not supported */
+#define SCAN_BY_TABLE                       0x0A
+#define SUPERVISORY_CONTROL                 0x10
+#define RTU_CONFIG                          0x20
+#define RETURN_RTU_CONFIG                   0x25
+#define REPORT_EXCEPTION_DATA               0x0D
+
+/* Function Code 0x00 (Basic Scan) Command codes */
+#define SIMPLE_STATUS_DATA                 0x01
+#define ALWAYS_RESERVED                    0x02
+#define TWO_BIT_STATUS                     0x04
+#define ANALOG_16_BIT                      0x08
+#define ACCUMULATOR_16_BIT                 0x40
+
+/* Function Code 0x03 (Special Calc) Command Codes */
+#define SPECIAL_CALC_RANGE                 0x00
+#define SPECIAL_CALC_ALL                   0x80
+
+/* Function Code 0x10 (Supervisory Control) Command Codes */
+#define SBO_SELECT_OPEN                    0x10
+#define SBO_SELECT_CLOSE                   0x11
+#define SBO_OPERATE                        0x20
+
+/* Function Code 0x20 (RTU Control) Command Codes */
+#define INIT_RTU_CONFIGURATION             0x00
+#define RESET_ACCUMULATOR                  0x11
+
+/* packet type */
+#define BASIC_SCAN_QUERY_PACKET            1
+#define BASIC_SCAN_RESPONSE_PACKET         2
+#define SPECIAL_CALC_REQUEST_ALL           3
+#define SPECIAL_CALC_RESPONSE_ALL          4
+#define SPECIAL_CALC_REQUEST_RANGE         5
+#define SPECIAL_CALC_RESPONSE_RANGE        6
+#define SCAN_INCLUSIVE_16_ANALOG_REQUEST   7
+#define SCAN_INCLUSIVE_16_ANALOG_RESPONSE  8
+#define SBO_SELECT_REQUEST                 9
+#define SBO_SELECT_RESPONSE                10
+#define SBO_OPERATE_REQUEST                11
+#define SBO_OPERATE_RESPONSE               12
+#define INIT_RTU_REQUEST                   13
+#define INIT_RTU_RESPONSE                  14
+#define RESET_ACC_REQUEST                  15
+#define RESET_ACC_RESPONSE                 16
+#define SPECIAL_CALC_RESPONSE              17
+
+/* packet length */
+#define CP2179_MIN_LENGTH                  7
+#define RESPONSE_HEADER_SIZE               7  /*includes addr, addr, function, status, port status, number of characters */
+#define BASIC_SCAN_REQ_LEN                 8
+#define SPECIAL_CALC_REQ_ALL_LEN           8
+#define SBO_OPERATE_REQ_LEN                8
+#define SPECIAL_CALC_REQ_RANGE_LEN         9
+#define SBO_SELECT_REQ_LEN                 9
+#define SBO_OPERATE_REPLY_LEN              9
+#define SBO_SELECT_REPLY_LEN               10
+
+#define PORT_CP2179    0
+static gboolean cp2179_telnet_clean = TRUE;
+
+
+/* Packet type Lookup */
+static const value_string cp2179_packettype_vals[] = {
+{BASIC_SCAN_QUERY_PACKET,               "Basic Scan Request"},
+{BASIC_SCAN_RESPONSE_PACKET,            "Basic Scan Response"},
+{SPECIAL_CALC_REQUEST_ALL,              "Special Calc Request All"},
+{SPECIAL_CALC_RESPONSE_ALL,             "Special Calc Response All"},
+{SPECIAL_CALC_REQUEST_RANGE,            "Special Calc Request a Range"},
+{SPECIAL_CALC_RESPONSE_RANGE,           "Special Calc Response a Range"},
+{SPECIAL_CALC_RESPONSE,                 "Special Calc Response"},
+{SCAN_INCLUSIVE_16_ANALOG_REQUEST,      "Scan Inclusive Request"},
+{SCAN_INCLUSIVE_16_ANALOG_RESPONSE,     "Scan Inclusive Response"},
+{SBO_SELECT_REQUEST,                    "SBO Select Request"},
+{SBO_SELECT_RESPONSE,                   "SBO Select Response"},
+{SBO_OPERATE_REQUEST,                   "SBO Operate Request"},
+{SBO_OPERATE_RESPONSE,                  "SBO Operate Response"},
+{INIT_RTU_REQUEST,                      "INIT RTU Request"},
+{INIT_RTU_RESPONSE,                     "INIT RTU Response"},
+{RESET_ACC_REQUEST,                     "RESET Accumulator Request"},
+{RESET_ACC_RESPONSE,                    "RESET Accumulator Response"},
+{-99,                                   "Unknown Function Code"},
+{ 0,                                    NULL }
+
+};
+
+static value_string_ext cp2179_packettype_vals_ext = VALUE_STRING_EXT_INIT(cp2179_packettype_vals);
+
+/* List contains request data  */
+typedef struct {
+    wmem_list_t *bs_request_frame_data;
+} cp2179_conversation;
+
+
+/* Function code Lookup */
+static const value_string FunctionCodenames[] = {
+{ BASIC_SCAN,                     "Basic Scan" },
+{ SCAN_INCLUSIVE,                 "Scan Inclusive"},
+{ SCAN_FOR_SPECIAL_CALC,          "Scan Floating Points" },
+{ SCAN_BY_TABLE,                  "Scan by Table" },
+{ SUPERVISORY_CONTROL,            "Supervisory Control" },
+{ RTU_CONFIG,                     "RTU Internal Control" },
+{ RETURN_RTU_CONFIG,              "Return RTU Config"},
+{ REPORT_EXCEPTION_DATA,          "Report Exception data"},
+{ 0,                              NULL }
+};
+
+/* Command code Lookup (FC00, FC03, FC10) */
+static const value_string cp2179_CommandCodeNames [] = {
+{ SIMPLE_STATUS_DATA,             "Simple Status" },
+{ ALWAYS_RESERVED,                "Reserved" },
+{ TWO_BIT_STATUS,                 "2 Bit Data Status" },
+{ ANALOG_16_BIT,                  "16 Bit Analog" },
+{ ACCUMULATOR_16_BIT,             "16 Bit Pulsed Accumulator" },
+{ SBO_SELECT_OPEN,                "SBO Open" },
+{ SBO_SELECT_CLOSE,               "SBO Close" },
+{ SBO_OPERATE,                    "SBO Operate" },
+{ SPECIAL_CALC_ALL,               "Request All Special Calc Data"},
+{ SPECIAL_CALC_RANGE,             "Request a Range of Special Calc"},
+{ 0,                              NULL }
+};
+
+static value_string_ext cp2179_CommandCodeNames_ext = VALUE_STRING_EXT_INIT(cp2179_CommandCodeNames);
+
+/* Function Code 0x20 Command Code Lookup */
+static const value_string cp2179_FC20_CommandCodeNames [] = {
+{ INIT_RTU_CONFIGURATION,         "Initialize RTU Config" },
+{ RESET_ACCUMULATOR,              "Accumulator Reset" },
+{ 0,                              NULL }
+};
+
+/* Holds Request information required to later decode a response  */
+typedef struct {
+   guint32  fnum;  /* frame number */
+   guint16  address_word;
+   guint8   function_code;
+   guint8   commmand_code;
+   guint16  numberofcharacters;
+   guint8   *requested_points;
+} bs_request_frame;
+
+
+static int proto_cp2179 = -1;
+
+static guint global_cp2179_tcp_port = PORT_CP2179; /* Port 0 (by default), adjustable by user prefs */
+
+/* Initialize the subtree pointers */
+static gint ett_cp2179 = -1;
+static gint ett_cp2179_header = -1;
+static gint ett_cp2179_addr = -1;
+static gint ett_cp2179_fc = -1;
+static gint ett_cp2179_data = -1;
+static gint ett_cp2179_subdata = -1;
+
+/* Initialize the protocol and registered fields */
+static int hf_cp2179_request_frame = -1;
+static int hf_cp2179_rtu_address = -1;
+static int hf_cp2179_master_address = -1;
+static int hf_cp2179_function_code = -1;
+static int hf_cp2179_nop_flag = -1;
+static int hf_cp2179_rst_flag = -1;
+static int hf_cp2179_reserved = -1;
+static int hf_cp2179_command_code = -1;
+static int hf_cp2179_command_code_fc20 = -1;
+static int hf_cp2179_sbo_request_point = -1;
+static int hf_cp2179_resetacc_request_point = -1;
+static int hf_cp2179_speccalc_request_point = -1;
+static int hf_cp2179_scaninc_startreq_point = -1;
+static int hf_cp2179_scaninc_stopreq_point = -1;
+static int hf_cp2179_number_characters = -1;
+static int hf_cp2179_analog_16bit = -1;
+static int hf_cp2179_accumulator = -1;
+static int hf_cp2179_crc = -1;
+static int hf_cp2179_data_field = -1;
+static int hf_cp2179_status_byte = -1;
+static int hf_cp2179_port_status_byte = -1;
+static int hf_cp2179_simplestatusbit  = -1;
+static int hf_cp2179_simplestatusbit0 = -1;
+static int hf_cp2179_simplestatusbit1 = -1;
+static int hf_cp2179_simplestatusbit2 = -1;
+static int hf_cp2179_simplestatusbit3 = -1;
+static int hf_cp2179_simplestatusbit4 = -1;
+static int hf_cp2179_simplestatusbit5 = -1;
+static int hf_cp2179_simplestatusbit6 = -1;
+static int hf_cp2179_simplestatusbit7 = -1;
+static int hf_cp2179_simplestatusbit8 = -1;
+static int hf_cp2179_simplestatusbit9 = -1;
+static int hf_cp2179_simplestatusbit10 = -1;
+static int hf_cp2179_simplestatusbit11 = -1;
+static int hf_cp2179_simplestatusbit12 = -1;
+static int hf_cp2179_simplestatusbit13 = -1;
+static int hf_cp2179_simplestatusbit14 = -1;
+static int hf_cp2179_simplestatusbit15 = -1;
+static int hf_cp2179_specialcalc       = -1;
+static int hf_cp2179_2bitstatus        = -1;
+static int hf_cp2179_2bitstatuschg0    = -1;
+static int hf_cp2179_2bitstatuschg1    = -1;
+static int hf_cp2179_2bitstatuschg2    = -1;
+static int hf_cp2179_2bitstatuschg3    = -1;
+static int hf_cp2179_2bitstatuschg4    = -1;
+static int hf_cp2179_2bitstatuschg5    = -1;
+static int hf_cp2179_2bitstatuschg6    = -1;
+static int hf_cp2179_2bitstatuschg7    = -1;
+static int hf_cp2179_2bitstatusstatus0 = -1;
+static int hf_cp2179_2bitstatusstatus1 = -1;
+static int hf_cp2179_2bitstatusstatus2 = -1;
+static int hf_cp2179_2bitstatusstatus3 = -1;
+static int hf_cp2179_2bitstatusstatus4 = -1;
+static int hf_cp2179_2bitstatusstatus5 = -1;
+static int hf_cp2179_2bitstatusstatus6 = -1;
+static int hf_cp2179_2bitstatusstatus7 = -1;
+
+static const int *cp2179_simplestatus_bits[] = {
+  &hf_cp2179_simplestatusbit0,
+  &hf_cp2179_simplestatusbit1,
+  &hf_cp2179_simplestatusbit2,
+  &hf_cp2179_simplestatusbit3,
+  &hf_cp2179_simplestatusbit4,
+  &hf_cp2179_simplestatusbit5,
+  &hf_cp2179_simplestatusbit6,
+  &hf_cp2179_simplestatusbit7,
+  &hf_cp2179_simplestatusbit8,
+  &hf_cp2179_simplestatusbit9,
+  &hf_cp2179_simplestatusbit10,
+  &hf_cp2179_simplestatusbit11,
+  &hf_cp2179_simplestatusbit12,
+  &hf_cp2179_simplestatusbit13,
+  &hf_cp2179_simplestatusbit14,
+  &hf_cp2179_simplestatusbit15,
+  NULL
+};
+
+static const int *cp2179_2bitstatus_bits[] = {
+  &hf_cp2179_2bitstatuschg0,
+  &hf_cp2179_2bitstatuschg1,
+  &hf_cp2179_2bitstatuschg2,
+  &hf_cp2179_2bitstatuschg3,
+  &hf_cp2179_2bitstatuschg4,
+  &hf_cp2179_2bitstatuschg5,
+  &hf_cp2179_2bitstatuschg6,
+  &hf_cp2179_2bitstatuschg7,
+  &hf_cp2179_2bitstatusstatus0,
+  &hf_cp2179_2bitstatusstatus1,
+  &hf_cp2179_2bitstatusstatus2,
+  &hf_cp2179_2bitstatusstatus3,
+  &hf_cp2179_2bitstatusstatus4,
+  &hf_cp2179_2bitstatusstatus5,
+  &hf_cp2179_2bitstatusstatus6,
+  &hf_cp2179_2bitstatusstatus7,
+  NULL
+};
+
+
+/**********************************************************************************************************/
+/* Clean all instances of 0xFFFF from Telnet payload to compensate for IAC control code (replace w/ 0xFF) */
+/* Function Duplicated from packet-telnet.c (unescape_and_tvbuffify_telnet_option)                        */
+/**********************************************************************************************************/
+static tvbuff_t *
+clean_telnet_iac(packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
+{
+  tvbuff_t     *telnet_tvb;
+  guint8       *buf;
+  const guint8 *spos;
+  guint8       *dpos;
+  int           skip_byte, len_remaining;
+
+  spos=tvb_get_ptr(tvb, offset, len);
+  buf=(guint8 *)g_malloc(len);
+  dpos=buf;
+  skip_byte = 0;
+  len_remaining = len;
+  while(len_remaining > 0){
+
+    /* Only analyze two sequential bytes of source tvb if we have at least two bytes left */
+    if (len_remaining > 1) {
+        /* If two sequential 0xFF's exist, increment skip_byte counter, decrement  */
+        /* len_remaining by 2 and copy a single 0xFF to dest tvb. */
+        if((spos[0]==0xff) && (spos[1]==0xff)){
+            skip_byte++;
+            len_remaining -= 2;
+            *(dpos++)=0xff;
+            spos+=2;
+            continue;
+        }
+    }
+    /* If we only have a single byte left, or there were no sequential 0xFF's, copy byte from src tvb to dest tvb */
+    *(dpos++)=*(spos++);
+    len_remaining--;
+  }
+  telnet_tvb = tvb_new_child_real_data(tvb, buf, len-skip_byte, len-skip_byte);
+  tvb_set_free_cb(telnet_tvb, g_free);
+  add_new_data_source(pinfo, telnet_tvb, "Processed Telnet Data");
+
+  return telnet_tvb;
+}
+
+/******************************************************************************************************/
+/* Code to Dissect Request frames */
+/******************************************************************************************************/
+static int
+dissect_request_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset, guint16 packet_type )
+{
+/* Set up structures needed to add the protocol subtree and manage it */
+    proto_tree *cp2179_proto_tree = NULL;
+    proto_tree *cp2179_addr_tree = NULL;
+    proto_tree *cp2179_fc_tree = NULL;
+
+    proto_item *cp2179_proto_item = NULL;
+
+    guint8 req_command_code = 0;
+    guint8 function_code = 0;
+
+    guint16 address_word = -1;
+    guint16 requestnumberofcharacters = 0;
+
+    cp2179_proto_item = proto_tree_add_item(tree, proto_cp2179, tvb, 0, -1, ENC_NA);
+    cp2179_proto_tree = proto_item_add_subtree(cp2179_proto_item, ett_cp2179_header);
+
+    /* RTU & Master Address are encoded into a 16-bit word */
+    address_word = tvb_get_letohs(tvb, offset);
+    cp2179_addr_tree = proto_tree_add_subtree_format(cp2179_proto_tree, tvb, offset, 2, ett_cp2179_addr, NULL,
+               "RTU Address: %d, Master Address: %d", (address_word & 0x7FF), ((address_word & 0xF800) >> 11) );
+
+    proto_tree_add_item(cp2179_addr_tree, hf_cp2179_rtu_address, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+    proto_tree_add_item(cp2179_addr_tree, hf_cp2179_master_address, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+    offset += 2;
+
+    /* Report the function code */
+    function_code = tvb_get_guint8(tvb, offset) & 0x3f;
+    cp2179_fc_tree = proto_tree_add_subtree_format(cp2179_proto_tree, tvb, offset, 1, ett_cp2179_fc, NULL,
+               "Function Code: %s (0x%02x)", val_to_str_const(function_code, FunctionCodenames, "Unknown Function Code"), function_code);
+
+    proto_tree_add_item(cp2179_fc_tree, hf_cp2179_function_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+    proto_tree_add_item(cp2179_fc_tree, hf_cp2179_reserved, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+    offset += 1;
+
+    /* Because the function code basic scan for simple status and function code Internal Control for INIT RTU have the same
+       command code. If the packet type is a INIT RTU request, interpret the command code as INIT RTU, or else report it as
+       basic scan simple status command code.*/
+    switch(packet_type)
+    {
+    case INIT_RTU_REQUEST:
+    case RESET_ACC_REQUEST:
+        proto_tree_add_item(cp2179_proto_tree,  hf_cp2179_command_code_fc20 , tvb, offset, 1, ENC_LITTLE_ENDIAN);
+        break;
+
+    case BASIC_SCAN_QUERY_PACKET:
+    case SCAN_INCLUSIVE_16_ANALOG_REQUEST:
+        req_command_code = tvb_get_guint8(tvb, offset);
+        /* Update Info column with useful information of Command Code Type */
+        col_append_fstr(pinfo->cinfo, COL_INFO, " [ %s ]", val_to_str_ext_const(req_command_code, &cp2179_CommandCodeNames_ext, "Unknown Command Code"));
+        proto_tree_add_item(cp2179_proto_tree, hf_cp2179_command_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+        break;
+
+    default:
+        proto_tree_add_item(cp2179_proto_tree, hf_cp2179_command_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+        break;
+    }
+    offset += 1;
+
+    requestnumberofcharacters = tvb_get_letohs(tvb, 4);
+    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_number_characters, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+    offset += 2;
+
+    /*If request number is greater than 0, data field in the request is not empty, we need to report the data field*/
+    if ( requestnumberofcharacters > 0 ){
+        /*Depends on the packet type, the data field should be dissect differently*/
+        switch (packet_type)
+        {
+            case SBO_SELECT_REQUEST:
+                proto_tree_add_item(cp2179_proto_tree, hf_cp2179_sbo_request_point, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+                offset += 1;
+                break;
+
+            /*Reset Accumulator request data field will always only has 1 byte. The Sequence ID of the Accumulator that it wants to reset*/
+            case RESET_ACC_REQUEST:
+                proto_tree_add_item(cp2179_proto_tree, hf_cp2179_resetacc_request_point, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+                offset += 1;
+                break;
+
+            /* A special calculation that requests for a range of points will have a list of sequence ID of the Special Calculation points */
+            case SPECIAL_CALC_REQUEST_RANGE:
+                do{
+                    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_speccalc_request_point, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+                    offset += 1;
+                }while(tvb_reported_length_remaining(tvb, offset) > 2);
+                break;
+
+            /*Scan Inclusive will have a starting sequence ID and a ending sequence ID in the data field.*/
+            case SCAN_INCLUSIVE_16_ANALOG_REQUEST:
+                do{
+                    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_scaninc_startreq_point, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+                    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_scaninc_stopreq_point, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
+                    offset += 2;
+                }while(tvb_reported_length_remaining(tvb, offset) > 2);
+                break;
+        }
+    }
+        /*report the last two bytes as CRC in the request*/
+    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_crc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+
+    return tvb_reported_length(tvb);
+}
+
+
+/******************************************************************************************************/
+/* Code to dissect Response frames  */
+/******************************************************************************************************/
+static int
+dissect_bs_response_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset, guint16 packet_type)
+{
+    /* Set up structures needed to add the protocol subtree and manage it */
+    proto_item *bs_response_item = NULL;
+    proto_item *cp2179_proto_item = NULL;
+    proto_item *cp2179_subdata_item = NULL;
+
+    proto_tree *cp2179_proto_tree = NULL;
+    proto_tree *cp2179_addr_tree = NULL;
+    proto_tree *cp2179_fc_tree = NULL;
+    proto_tree *cp2179_data_tree = NULL;
+
+    cp2179_conversation  *conv;
+    guint32 req_frame_num;
+    guint16 req_address_word;
+    guint8  req_command_code;
+    gboolean request_found = FALSE;
+    bs_request_frame *request_data;
+
+    gint analogtestvalue = 0;
+    gint analog16_num = 0;
+    gint point_num = 0;
+
+    guint function_code;
+    guint simplestatusseq = 0x30;
+
+    guint16 address_word = 0;
+    guint16 numberofcharacters = -1;
+
+    gfloat specialcalvalue = 0;
+
+    cp2179_proto_item = proto_tree_add_item(tree, proto_cp2179, tvb, 0, -1, ENC_NA);
+    cp2179_proto_tree = proto_item_add_subtree(cp2179_proto_item, ett_cp2179_header);
+
+    /* RTU & Master Address are encoded into a 16-bit word */
+    address_word = tvb_get_letohs(tvb, offset);
+
+    cp2179_addr_tree = proto_tree_add_subtree_format(cp2179_proto_tree, tvb, offset, 2, ett_cp2179_addr, NULL,
+                   "RTU Address: %d, Master Address: %d", (address_word & 0x7FF), ((address_word & 0xF800) >> 11) );
+
+    proto_tree_add_item(cp2179_addr_tree, hf_cp2179_rtu_address, tvb, 0, 2, ENC_LITTLE_ENDIAN);
+    proto_tree_add_item(cp2179_addr_tree, hf_cp2179_master_address, tvb, 0, 2, ENC_LITTLE_ENDIAN);
+    offset += 2;
+
+    /*The response always echos the function code in request, except when the RTU can't perform the required function.
+    It may set the NOP or RST bit. Bit 0 to bit 5 is the field for function codes. Bit 6 is NOP bit. Bit 7 is RST bit. */
+    function_code = tvb_get_guint8(tvb, offset) & 0x3f;
+
+    cp2179_fc_tree = proto_tree_add_subtree_format(cp2179_proto_tree, tvb, offset, 1, ett_cp2179_fc, NULL,
+               "Function Code: %s (0x%02x)", val_to_str_const(function_code, FunctionCodenames, "Unknown Function Code"), function_code);
+
+    proto_tree_add_item(cp2179_fc_tree, hf_cp2179_function_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+    proto_tree_add_item(cp2179_fc_tree, hf_cp2179_nop_flag, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+    proto_tree_add_item(cp2179_fc_tree, hf_cp2179_rst_flag, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+
+    offset += 1;
+
+    /* Status Byte & Port Status */
+    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_status_byte, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+    offset += 1;
+    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_port_status_byte, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+    offset += 1;
+
+    /* Number of characters */
+    numberofcharacters = tvb_get_letohs(tvb, 5);
+    proto_tree_add_item(cp2179_proto_tree, hf_cp2179_number_characters, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+    offset += 2;
+
+    /* get the converstation data */
+    conv = (cp2179_conversation *)p_get_proto_data(wmem_file_scope(), pinfo, proto_cp2179, 0);
+
+    if (conv) {
+        wmem_list_frame_t *frame = wmem_list_head(conv->bs_request_frame_data);
+        /* Cycle through all logged instances of request frames, looking for request frame number that occurred immediately
+           prior to current frame number that has a matching address word */
+        while (frame && !request_found) {
+            request_data = (bs_request_frame *)wmem_list_frame_data(frame);
+            req_frame_num = request_data->fnum;
+            req_command_code = request_data->commmand_code;
+            req_address_word = request_data->address_word;
+                if ((pinfo->fd->num > req_frame_num) && (req_address_word == address_word)) {
+                    bs_response_item = proto_tree_add_uint(cp2179_proto_tree, hf_cp2179_request_frame, tvb, 0, 0, req_frame_num);
+                    PROTO_ITEM_SET_GENERATED(bs_response_item);
+                    request_found = TRUE;
+                }
+                frame = wmem_list_frame_next(frame);
+        }
+
+        if (request_found)
+        {
+            switch (packet_type)
+            {
+                case SBO_SELECT_RESPONSE:
+                case SBO_OPERATE_RESPONSE:
+                case RESET_ACC_RESPONSE:
+                case INIT_RTU_RESPONSE:
+
+                    if ( numberofcharacters > 0 ){
+                        /*Based on the packet type, change the displayed messages*/
+                        if ( packet_type == SBO_SELECT_RESPONSE ){
+                            proto_tree_add_item(cp2179_proto_tree, hf_cp2179_sbo_request_point, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+                            offset += 1;
+                        }
+                        if ( packet_type == RESET_ACC_RESPONSE ){
+                            proto_tree_add_item(cp2179_proto_tree, hf_cp2179_resetacc_request_point, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+                            offset += 1;
+                        }
+                    }
+                    break;
+
+                case SPECIAL_CALC_RESPONSE:
+                    /* Based on the command code from the corresponding request, dissect the data field differently.
+                       If required a range of Special calculation, display the requested sequence ID and corresponding
+                       values. The requested sequence number is obtained from the previous request frame.  */
+                    cp2179_data_tree = proto_tree_add_subtree(cp2179_proto_tree, tvb, offset, numberofcharacters, ett_cp2179_data, NULL, "CP2179 Data Field");
+
+                    if (req_command_code == SPECIAL_CALC_ALL ){
+                        do{
+                            specialcalvalue = tvb_get_letohieee_float(tvb, offset );
+                            proto_tree_add_float_format(cp2179_data_tree, hf_cp2179_specialcalc, tvb, offset, 4, specialcalvalue,
+                                "Special Calculation %u : %f", point_num, specialcalvalue);
+                            point_num += 1;
+                            offset += 4;
+                        }while(tvb_reported_length_remaining(tvb, offset) > 2);
+                    }
+                    /*If it request all the special calculation data, dissect all of them and associated a sequence ID with it.*/
+                    else if (req_command_code == SPECIAL_CALC_RANGE ){
+                        do{
+                            specialcalvalue = tvb_get_letohieee_float(tvb, offset );
+                            proto_tree_add_float_format(cp2179_data_tree, hf_cp2179_specialcalc, tvb, offset, 4, specialcalvalue,
+                                "Special Calculation %u : %f",  request_data->requested_points[point_num], specialcalvalue);
+                            point_num += 1;
+                            offset += 4;
+                        }while(tvb_reported_length_remaining(tvb, offset) > 2);
+                    }
+                    break;
+
+                case SCAN_INCLUSIVE_16_ANALOG_RESPONSE:
+
+                    cp2179_data_tree = proto_tree_add_subtree(cp2179_proto_tree, tvb, offset, numberofcharacters, ett_cp2179_data, NULL, "CP2179 Data Field");
+
+                    /* Update Info column with useful information of Command Code Type */
+                    col_append_fstr(pinfo->cinfo, COL_INFO, " [ %s ]", val_to_str_ext_const(req_command_code, &cp2179_CommandCodeNames_ext, "Unknown Command Code"));
+
+                    /*Report the values of the requested SCAN inclusive data. To figure out which sequence ID the values in the response associated with,
+                    we read the bs_request_frame information and show the corresponding sequence ID of the data in response frame.*/
+                    do{
+                        analogtestvalue = (gint16)tvb_get_letohs(tvb, offset);
+                        proto_tree_add_uint_format(cp2179_data_tree, hf_cp2179_analog_16bit, tvb, offset, 2, request_data->requested_points[point_num],
+                                                   "Analog (16 bit) %u : %i",  request_data->requested_points[point_num], analogtestvalue);
+                        point_num += 1;
+                        offset += 2;
+                    }while(tvb_reported_length_remaining(tvb, offset) > 2);
+
+                    break;
+
+                case BASIC_SCAN_RESPONSE_PACKET:
+                {
+                    cp2179_data_tree = proto_tree_add_subtree(cp2179_proto_tree, tvb, offset, numberofcharacters, ett_cp2179_data, NULL, "CP2179 Data Field");
+
+                    /* Update Info column with useful information of Command Code Type */
+                    col_append_fstr(pinfo->cinfo, COL_INFO, " [ %s ]", val_to_str_ext_const(req_command_code, &cp2179_CommandCodeNames_ext, "Unknown Command Code"));
+
+                    switch (req_command_code)
+                    {
+                        /* Based the command code from the request frame, we dissect the response data differently.
+                           For example, if the request packet has command byte as ANALOG_16_BIT, the
+                           the data field in the response should be dissected as 16-bit signed integer(s). */
+                        case ACCUMULATOR_16_BIT:
+                            do{
+                                analogtestvalue = tvb_get_letohs(tvb, offset);
+                                proto_tree_add_uint_format(cp2179_data_tree, hf_cp2179_accumulator, tvb, offset, 2, analog16_num,
+                                                           "Accumulator %u : %u", analog16_num, analogtestvalue);
+                                analog16_num += 1;
+                                offset += 2;
+                            }while(tvb_reported_length_remaining(tvb, offset) > 2);
+
+                            break;
+
+                        case ANALOG_16_BIT:
+                            do{
+                                analogtestvalue =(gint16)tvb_get_letohs(tvb, offset);
+                                proto_tree_add_uint_format(cp2179_data_tree, hf_cp2179_analog_16bit, tvb, offset, 2, analog16_num,
+                                                           "Analog (16 bit) %u : %i", analog16_num, analogtestvalue);
+                                analog16_num += 1;
+                                offset += 2;
+                            }while(tvb_reported_length_remaining(tvb, offset) > 2);
+
+                            break;
+
+                        case SIMPLE_STATUS_DATA:
+                            do{
+                                cp2179_subdata_item = proto_tree_add_bitmask(cp2179_data_tree, tvb, offset, hf_cp2179_simplestatusbit,
+                                                       ett_cp2179_subdata, cp2179_simplestatus_bits, ENC_LITTLE_ENDIAN);
+                                proto_item_set_text(cp2179_subdata_item, "Simple Status Point 0x%x", simplestatusseq);
+
+                                simplestatusseq += 1;
+                                offset += 2;
+                            }while(tvb_reported_length_remaining(tvb, offset) > 2);
+
+                            break;
+
+                        case TWO_BIT_STATUS:
+                            do{
+                                cp2179_subdata_item = proto_tree_add_bitmask(cp2179_data_tree, tvb, offset, hf_cp2179_2bitstatus,
+                                                       ett_cp2179_subdata, cp2179_2bitstatus_bits, ENC_LITTLE_ENDIAN);
+                                proto_item_set_text(cp2179_subdata_item, "2 Bit Status Point 0x%x", simplestatusseq);
+
+                                simplestatusseq += 1;
+                                offset += 2;
+                            }while(tvb_reported_length_remaining(tvb, offset) > 2);
+
+                            break;
+                    } /* end of command code switch */
+
+                } /* end of basic scan response switch */
+
+                break;
+
+            } /* end of packet type switch */
+
+            proto_tree_add_item(cp2179_proto_tree, hf_cp2179_crc, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+
+        } /* request found */
+
+    } /* conversation data found */
+
+    if (!request_found) {
+        proto_item_append_text(bs_response_item, ", No Request found");
+        return 0;
+    }
+
+    return tvb_reported_length(tvb);
+}
+
+/******************************************************************************************************/
+/* Load Request information into bs request struct */
+/******************************************************************************************************/
+static bs_request_frame* copy_bs_request_frame(tvbuff_t *tvb  )
+{
+ /* Set up structures needed to add the protocol request and use it for dissecting response packet */
+    guint offset = 0;
+    guint8 index=0 ;
+    bs_request_frame *frame;
+    guint16 num_objects=0;
+
+    /* get a new frame and initialize it */
+    frame = wmem_new(wmem_file_scope(), bs_request_frame);
+
+    /* update the data within the structure frame */
+    frame->address_word = tvb_get_letohs(tvb, offset); offset +=2;
+    frame->function_code = tvb_get_guint8(tvb, offset); offset +=1;
+    frame->commmand_code = tvb_get_guint8(tvb, offset); offset +=1;
+    frame->numberofcharacters = tvb_get_letohs(tvb, offset);offset +=2;
+
+    /*Keep track of the request data field in a request.
+      Such as SCAN INCLUSIVE request contains a Start Sequence Number and an Ending Sequence Number. */
+    if (frame->function_code == SCAN_INCLUSIVE) {
+        guint8 startpt, endpt;
+        startpt = tvb_get_guint8(tvb, offset);
+        endpt = tvb_get_guint8(tvb, offset+1);
+        num_objects = (endpt - startpt) + 1;
+        frame->requested_points = (guint8 *)wmem_alloc(wmem_file_scope(), num_objects * sizeof(guint8));
+
+        /* We have a range of 'request' points */
+        for (index = 0; index < num_objects; index++) {
+            frame->requested_points[index] = startpt;
+            startpt++;
+        }
+        /* offset += 2; */
+    }
+    /* Get Details for all Requested Points */
+    else {
+        num_objects = frame->numberofcharacters;
+        frame->requested_points = (guint8 *)wmem_alloc(wmem_file_scope(), num_objects * sizeof(guint8));
+        for (index = 0; index < num_objects; index++) {
+            frame->requested_points[index] = tvb_get_guint8(tvb, offset);
+            offset += 1;
+        }
+
+    }
+
+    return frame;
+}
+
+
+
+/******************************************************************************************************/
+/* Classify the different packet type  */
+/******************************************************************************************************/
+static int
+classify_packet_type(tvbuff_t *tvb)
+{
+    int packet_type = -1;
+    guint8 function_code;
+    guint8 command_code;
+    guint16 requestnumberofcharacters = 0;
+    guint16 responsenumberofcharacters = 0;
+    guint16 packet_length = 0;
+
+
+    packet_length = tvb_reported_length(tvb);
+    /*Get function code*/
+    function_code = tvb_get_guint8(tvb, 2);
+    /*Get command codes */
+    command_code = tvb_get_guint8(tvb, 3);
+    /* Get number of characters */
+    requestnumberofcharacters = tvb_get_letohs(tvb, 4);
+    responsenumberofcharacters = tvb_get_letohs(tvb, 5);
+
+    /*The response always echos the function code in request, except when the RTU can't perform the required function.
+    It may set the NOP or RST bit. Bit 0 to bit 5 is the field for function codes. Bit 6 is NOP bit. Bit 7 is RST bit. */
+
+    /*Remove NOP and RST bit*/
+    function_code = function_code & 0x3f ;
+
+    /*2179 protocol frames doesn't have data tells you whether it is a request or a response. We will decide what packet type is based on
+    multiple factors, function code, command code, the length of the packet*/
+    switch (function_code ){
+        case BASIC_SCAN:
+            /*Basic scan request message, the number of characters is always 0 and length is fixed*/
+            if ( (requestnumberofcharacters == 0) && (packet_length == BASIC_SCAN_REQ_LEN) ) {
+                packet_type = BASIC_SCAN_QUERY_PACKET ; /* supported */
+            }
+            else if ( (responsenumberofcharacters > 0) && (packet_length > BASIC_SCAN_REQ_LEN) ) {
+                packet_type = BASIC_SCAN_RESPONSE_PACKET; /* supported */
+            }
+
+            break;
+
+        case SUPERVISORY_CONTROL:
+            /*SBO select request messages always has number of characters equals to 1 and SBO length is fixed*/
+            if ( (requestnumberofcharacters == 1) && (packet_length == SBO_SELECT_REQ_LEN) ) {
+                packet_type = SBO_SELECT_REQUEST; /* supported */
+            }
+            /*SBO select response always has number of characters equals to 1 and SBO length is fixed. */
+            else if ( (responsenumberofcharacters == 1) && (packet_length == SBO_SELECT_REPLY_LEN) ) {
+                packet_type = SBO_SELECT_RESPONSE; /* supported */
+            }
+            /*SBO operate request always has number of characters as 0 */
+            else if (requestnumberofcharacters == 0) {
+                if ( (packet_length == SBO_OPERATE_REQ_LEN) && (command_code == SBO_OPERATE) ) {
+                    packet_type = SBO_OPERATE_REQUEST; /* supported */
+                }
+            }
+            /*SBO operate response always has number of characters as 0 */
+            else if (responsenumberofcharacters == 0) {
+                if (packet_length == SBO_OPERATE_REPLY_LEN) {
+                    packet_type = SBO_OPERATE_RESPONSE; /* supported */
+                }
+            }
+
+            break;
+
+        case SCAN_FOR_SPECIAL_CALC:
+            /*Scan for special cal has to command code associated with it, requests all special calculation data or a range of it */
+            if ( (requestnumberofcharacters == 0) && (command_code == SPECIAL_CALC_ALL ) ) {
+                packet_type = SPECIAL_CALC_REQUEST_ALL; /* supported */
+            }
+            else if ( (requestnumberofcharacters > 0) && (command_code == SPECIAL_CALC_RANGE ) ) {
+                packet_type = SPECIAL_CALC_REQUEST_RANGE; /* supported */
+            }
+            /*If a packet has SCAN_FOR_SPECIAL_CAL as function code and it is not a request, then it is a response */
+            else if ( (responsenumberofcharacters > 0) && (packet_length == (responsenumberofcharacters + 9) ) ) {
+                packet_type = SPECIAL_CALC_RESPONSE; /* supported */
+            }
+
+            break;
+        /*Scan Inclusive request always has request number of characters equals to 2 and a fixed command code */
+        case SCAN_INCLUSIVE:
+            /*If a packet has SCAN Inclusive function code and it is not a request, then it is a SCAN Inclusive response*/
+            if ( (responsenumberofcharacters > 0) ) {
+                packet_type = SCAN_INCLUSIVE_16_ANALOG_RESPONSE; /* supported */
+            }
+
+            if( (command_code == ANALOG_16_BIT) && (requestnumberofcharacters == 2) ) {
+                packet_type = SCAN_INCLUSIVE_16_ANALOG_REQUEST; /* supported */
+            }
+
+            break;
+
+        case RTU_CONFIG:
+            if (responsenumberofcharacters == 0) {
+                packet_type = INIT_RTU_RESPONSE;
+            }
+            if ( (requestnumberofcharacters == 0) && (command_code == INIT_RTU_CONFIGURATION) ) {
+                packet_type = INIT_RTU_REQUEST;
+            }
+
+            if (responsenumberofcharacters == 1) {
+                packet_type = RESET_ACC_RESPONSE;
+            }
+            if ( (requestnumberofcharacters == 1) && (command_code == RESET_ACCUMULATOR) ) {
+                packet_type = RESET_ACC_REQUEST;
+            }
+            break;
+        default :
+            packet_type = -99;
+            break;
+    }
+
+    return packet_type;
+}
+
+
+
+/******************************************************************************************************/
+/* Code to dissect CP2179 protocol packets */
+/******************************************************************************************************/
+static int
+dissect_cp2179_pdu(tvbuff_t *cp2179_tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+    int offset = 0;
+    gint16 packet_type;
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "CP2179");
+    col_clear(pinfo->cinfo,COL_INFO);
+
+    packet_type = classify_packet_type(cp2179_tvb);
+    /* set information for Information column for CP2179 */
+    col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str_ext_const(packet_type, &cp2179_packettype_vals_ext, "Unknown Packet Type"));
+
+    if (!pinfo->fd->flags.visited){
+        conversation_t       *conversation = NULL;
+        cp2179_conversation      *bs_conv_data = NULL;
+
+        /* Find a conversation, create a new if no one exists */
+        conversation = find_or_create_conversation(pinfo);
+        bs_conv_data = (cp2179_conversation *)conversation_get_proto_data(conversation, proto_cp2179);
+
+        if (bs_conv_data == NULL){
+           bs_conv_data = wmem_new(wmem_file_scope(), cp2179_conversation);
+           bs_conv_data->bs_request_frame_data = wmem_list_new(wmem_file_scope());
+           conversation_add_proto_data(conversation, proto_cp2179, (void *)bs_conv_data);
+        }
+
+        p_add_proto_data(wmem_file_scope(), pinfo, proto_cp2179, 0, bs_conv_data);
+
+        if ((packet_type == BASIC_SCAN_QUERY_PACKET) || (packet_type == SBO_SELECT_REQUEST)
+           ||(packet_type == SPECIAL_CALC_REQUEST_ALL)||(packet_type == SBO_OPERATE_REQUEST)
+           ||(packet_type == SPECIAL_CALC_REQUEST_RANGE)||(packet_type == INIT_RTU_REQUEST)
+           ||(packet_type == RESET_ACC_REQUEST)||(packet_type == SCAN_INCLUSIVE_16_ANALOG_REQUEST)) {
+
+            /*fill the bs request frame. It holds the request information.*/
+            bs_request_frame    *frame_ptr = NULL;
+            frame_ptr = copy_bs_request_frame(cp2179_tvb);
+
+            /*also hold the current frame number*/
+            frame_ptr->fnum = pinfo->fd->num;
+            wmem_list_prepend(bs_conv_data->bs_request_frame_data, frame_ptr);
+        }
+    } /* !visited */
+
+    if (tvb_reported_length_remaining(cp2179_tvb, offset) > 0){
+        switch (packet_type){
+            case BASIC_SCAN_QUERY_PACKET:
+            case SBO_SELECT_REQUEST:
+            case SBO_OPERATE_REQUEST:
+            case SPECIAL_CALC_REQUEST_ALL:
+            case SPECIAL_CALC_REQUEST_RANGE:
+            case SCAN_INCLUSIVE_16_ANALOG_REQUEST:
+            case RESET_ACC_REQUEST:
+            case INIT_RTU_REQUEST:
+                dissect_request_frame(cp2179_tvb, tree, pinfo, offset, packet_type);
+                break;
+
+            case BASIC_SCAN_RESPONSE_PACKET:
+            case SBO_SELECT_RESPONSE:
+            case SBO_OPERATE_RESPONSE:
+            case SPECIAL_CALC_RESPONSE:
+            case SCAN_INCLUSIVE_16_ANALOG_RESPONSE:
+            case INIT_RTU_RESPONSE:
+            case RESET_ACC_RESPONSE:
+                dissect_bs_response_frame(cp2179_tvb, tree, pinfo, offset, packet_type);
+                break;
+            default:
+                break;
+        } /* packet type */
+    } /* length remaining */
+
+    return tvb_reported_length(cp2179_tvb);
+}
+
+
+/******************************************************************************************************/
+/* Dissect (and possibly Re-assemble) CP2179 protocol payload data */
+/******************************************************************************************************/
+static int
+dissect_cp2179(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+    tvbuff_t *cp2179_tvb;
+    gint length = tvb_reported_length(tvb);
+
+   /* Check for the packet length, a 2179 Message is at least 7 byte long*/
+    if(length < CP2179_MIN_LENGTH){
+        return 0;
+    }
+
+    if((pinfo->srcport) && cp2179_telnet_clean){
+        cp2179_tvb = clean_telnet_iac(pinfo, tvb, 0, length);
+    }
+    else{
+        /* cp2179_tvb = tvb_new_subset( tvb, 0, length, length); */
+        cp2179_tvb = tvb_new_subset_length( tvb, 0, length);
+    }
+
+    dissect_cp2179_pdu(cp2179_tvb, pinfo, tree, data);
+
+    return length;
+}
+
+void proto_reg_handoff_cp2179(void);
+
+void
+proto_register_cp2179(void)
+{
+    static hf_register_info hf[] =
+    {
+        { &hf_cp2179_request_frame,
+            { "Request Frame", "cp2179.request_frame",
+            FT_FRAMENUM, BASE_NONE,
+            NULL, 0x0,
+            NULL, HFILL }
+        },
+
+        { &hf_cp2179_rtu_address,
+            { "RTU Address", "cp2179.RTUAddress",
+            FT_UINT16, BASE_DEC,
+            NULL, 0x7FF,
+            NULL, HFILL }
+        },
+
+       { &hf_cp2179_master_address,
+            { "Master Address", "cp2179.MasterAddress",
+            FT_UINT16, BASE_DEC,
+            NULL, 0xF800,
+            NULL, HFILL }
+        },
+        { &hf_cp2179_function_code,
+            { "Function Code", "cp2179.functioncode",
+            FT_UINT8, BASE_HEX,
+            VALS(FunctionCodenames), 0x3F,
+            NULL, HFILL }
+        },
+
+        { &hf_cp2179_nop_flag,
+            { "NOP Flag", "cp2179.nop_flag",
+            FT_UINT8, BASE_DEC,
+            NULL, 0x40,
+            NULL, HFILL }
+        },
+
+        { &hf_cp2179_rst_flag,
+            { "RST Flag", "cp2179.rst_flag",
+            FT_UINT8, BASE_DEC,
+            NULL, 0x80,
+            NULL, HFILL }
+        },
+
+        { &hf_cp2179_reserved,
+            { "Reserved Bits", "cp2179.Reserved",
+            FT_UINT8, BASE_DEC,
+            NULL, 0xC0,
+            NULL, HFILL }
+        },
+
+        { &hf_cp2179_command_code,
+            { "Command Code", "cp2179.commandcode",
+            FT_UINT8, BASE_HEX,
+            VALS(cp2179_CommandCodeNames), 0x0,
+            NULL, HFILL }
+        },
+
+        { &hf_cp2179_command_code_fc20,
+            { "Command Code (FC 0x20)", "cp2179.commandcodeinitrtu",
+            FT_UINT8, BASE_HEX,
+            VALS(cp2179_FC20_CommandCodeNames), 0x0,
+            NULL, HFILL }
+        },
+       { &hf_cp2179_status_byte,
+            { "RTU Status", "cp2179.rtustatus",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+       { &hf_cp2179_port_status_byte,
+            { "Port Status", "cp2179.portstatus",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+       { &hf_cp2179_sbo_request_point,
+            { "SBO Request Point", "cp2179.sbo_requestpoint",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+       { &hf_cp2179_resetacc_request_point,
+            { "Reset Accumulator Request Point", "cp2179.resetacc_requestpoint",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+       { &hf_cp2179_speccalc_request_point,
+            { "Special Calc Request Point", "cp2179.speccalc_requestpoint",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+       { &hf_cp2179_scaninc_startreq_point,
+            { "Start Request Point", "cp2179.scaninc_startreq_point",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+       { &hf_cp2179_scaninc_stopreq_point,
+            { "Stop Request Point", "cp2179.scaninc_stopreq_point",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+      { &hf_cp2179_number_characters,
+            { "Number of Characters", "cp2179.numberofcharacters",
+            FT_UINT16, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+      { &hf_cp2179_crc,
+            { "CRC", "cp2179.crc",
+            FT_UINT16, BASE_HEX,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+      { &hf_cp2179_data_field,
+            { "Data Field", "cp2179.datafield",
+            FT_UINT8, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+
+      { &hf_cp2179_accumulator,
+            { "Accumulator", "cp2179.accumulator",
+            FT_UINT16, BASE_DEC,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+
+      { &hf_cp2179_specialcalc,
+            { "Special Calc", "cp2179.specialcalc",
+            FT_FLOAT, BASE_NONE,
+            0x0, 0x0,
+            NULL, HFILL }
+        },
+
+      { &hf_cp2179_analog_16bit,
+         { "Analog 16-bit", "cp2179.analogdata",
+         FT_UINT16, BASE_DEC,
+         0x0, 0x0,
+         NULL, HFILL }
+        },
+      { &hf_cp2179_simplestatusbit,
+         { "Simple Status Bit", "cp2179.simplestatusbit",
+         FT_UINT16, BASE_HEX,
+         NULL, 0x0,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit0,
+         { "Simple Status bit 0", "cp2179.simplestatusbit0",
+         FT_BOOLEAN, 16,
+         NULL, 0x0001,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit1,
+         { "Simple Status bit 1", "cp2179.simplestatusbit1",
+         FT_BOOLEAN, 16,
+         NULL, 0x0002,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit2,
+         { "Simple Status bit 2", "cp2179.simplestatusbit2",
+         FT_BOOLEAN, 16,
+         NULL, 0x0004,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit3,
+         { "Simple Status bit 3", "cp2179.simplestatusbit3",
+         FT_BOOLEAN, 16,
+         NULL, 0x0008,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit4,
+         { "Simple Status bit 4", "cp2179.simplestatusbit4",
+         FT_BOOLEAN, 16,
+         NULL, 0x0010,
+         NULL, HFILL }
+      },
+
+      { &hf_cp2179_simplestatusbit5,
+         { "Simple Status bit 5", "cp2179.simplestatusbit5",
+         FT_BOOLEAN, 16,
+         NULL, 0x0020,
+         NULL, HFILL }
+      },
+
+      { &hf_cp2179_simplestatusbit6,
+         { "Simple Status bit 6", "cp2179.simplestatusbit6",
+         FT_BOOLEAN, 16,
+         NULL, 0x0040,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit7,
+         { "Simple Status bit 7", "cp2179.simplestatusbit7",
+         FT_BOOLEAN, 16,
+         NULL, 0x0080,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit8,
+         { "Simple Status bit 8", "cp2179.simplestatusbit8",
+         FT_BOOLEAN, 16,
+         NULL, 0x0100,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit9,
+         { "Simple Status bit 9", "cp2179.simplestatusbit9",
+         FT_BOOLEAN, 16,
+         NULL, 0x0200,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit10,
+         { "Simple Status bit 10", "cp2179.simplestatusbit10",
+         FT_BOOLEAN, 16,
+         NULL, 0x0400,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit11,
+         { "Simple Status bit 11", "cp2179.simplestatusbit11",
+         FT_BOOLEAN, 16,
+         NULL, 0x0800,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit12,
+         { "Simple Status bit 12", "cp2179.simplestatusbit12",
+         FT_BOOLEAN, 16,
+         NULL, 0x1000,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_simplestatusbit13,
+         { "Simple Status bit 13", "cp2179.simplestatusbit13",
+         FT_BOOLEAN, 16,
+         NULL, 0x2000,
+         NULL, HFILL }
+      },
+
+      { &hf_cp2179_simplestatusbit14,
+         { "Simple Status bit 14", "cp2179.simplestatusbit14",
+         FT_BOOLEAN, 16,
+         NULL, 0x4000,
+         NULL, HFILL }
+      },
+
+      { &hf_cp2179_simplestatusbit15,
+         { "Simple Status bit 15", "cp2179.simplestatusbit15",
+         FT_BOOLEAN, 16,
+         NULL, 0x8000,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatus,
+         { "2 Bit Status", "cp2179.twobitstatus",
+         FT_UINT16, BASE_HEX,
+         NULL, 0x0,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatuschg0,
+         { "2 Bit Status Change 0", "cp2179.twobitstatuschg0",
+         FT_BOOLEAN, 16,
+         NULL, 0x0001,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatuschg1,
+         { "2 Bit Status Change 1", "cp2179.twobitstatuschg1",
+         FT_BOOLEAN, 16,
+         NULL, 0x0002,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatuschg2,
+         { "2 Bit Status Change 2", "cp2179.twobitstatuschg2",
+         FT_BOOLEAN, 16,
+         NULL, 0x0004,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatuschg3,
+         { "2 Bit Status Change 3", "cp2179.twobitstatuschg3",
+         FT_BOOLEAN, 16,
+         NULL, 0x0008,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatuschg4,
+         { "2 Bit Status Change 4", "cp2179.twobitstatuschg4",
+         FT_BOOLEAN, 16,
+         NULL, 0x0010,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatuschg5,
+         { "2 Bit Status Change 5", "cp2179.twobitstatuschg5",
+         FT_BOOLEAN, 16,
+         NULL, 0x0020,
+         NULL, HFILL }
+      },
+
+      { &hf_cp2179_2bitstatuschg6,
+         { "2 Bit Status Change 6", "cp2179.twobitstatuschg6",
+         FT_BOOLEAN, 16,
+         NULL, 0x0040,
+         NULL, HFILL }
+      },
+
+      { &hf_cp2179_2bitstatuschg7,
+         {  "2 Bit Status Change 7", "cp2179.twobitstatuschg7",
+         FT_BOOLEAN, 16,
+         NULL, 0x0080,
+         NULL, HFILL }
+      },
+
+      { &hf_cp2179_2bitstatusstatus0,
+         { "2 Bit Status bit 0", "cp2179.twobitstatusbit0",
+         FT_BOOLEAN, 16,
+         NULL, 0x0100,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatusstatus1,
+         { "2 Bit Status bit 1", "cp2179.twobitstatusbit1",
+         FT_BOOLEAN, 16,
+         NULL, 0x0200,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatusstatus2,
+         { "2 Bit Status bit 2", "cp2179.twobitstatusbit2",
+         FT_BOOLEAN, 16,
+         NULL, 0x0400,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatusstatus3,
+         { "2 Bit Status bit 3", "cp2179.twobitstatusbit3",
+         FT_BOOLEAN, 16,
+         NULL, 0x0800,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatusstatus4,
+         { "2 Bit Status bit 4", "cp2179.twobitstatusbit4",
+         FT_BOOLEAN, 16,
+         NULL, 0x1000,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatusstatus5,
+         { "2 Bit Status bit 5", "cp2179.twobitstatusbit5",
+         FT_BOOLEAN, 16,
+         NULL, 0x2000,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatusstatus6,
+         { "2 Bit Status bit 6", "cp2179.twobitstatusbit6",
+         FT_BOOLEAN, 16,
+         NULL, 0x4000,
+         NULL, HFILL }
+      },
+      { &hf_cp2179_2bitstatusstatus7,
+         { "2 Bit Status bit 7", "cp2179.twobitstatusbit7",
+         FT_BOOLEAN, 16,
+         NULL, 0x8000,
+         NULL, HFILL }
+}
+    };
+
+    /* Setup protocol subtree array */
+    static gint *ett[] = {
+      &ett_cp2179,
+      &ett_cp2179_header,
+      &ett_cp2179_addr,
+      &ett_cp2179_fc,
+      &ett_cp2179_data,
+      &ett_cp2179_subdata
+
+    };
+
+    module_t *cp2179_module;
+
+    proto_cp2179 = proto_register_protocol ("CP2179 Protocol", "CP2179", "cp2179");
+    new_register_dissector("cp2179", dissect_cp2179, proto_cp2179);
+    proto_register_field_array(proto_cp2179, hf, array_length(hf));
+    proto_register_subtree_array(ett, array_length(ett));
+
+    /* Register required preferences for CP2179 Encapsulated-over-TCP decoding */
+    cp2179_module = prefs_register_protocol(proto_cp2179, proto_reg_handoff_cp2179);
+
+    /* Default TCP Port, allows for "user" port either than 0. */
+    prefs_register_uint_preference(cp2179_module, "tcp.port", "CP 2179 Protocol Port",
+                       "Set the TCP port for CP 2179 Protocol packets (if other"
+                       " than the default of 0)",
+                       10, &global_cp2179_tcp_port);
+
+    /* Telnet protocol IAC (0xFF) processing; defaults to TRUE to allow Telnet Encapsulated Data */
+    prefs_register_bool_preference(cp2179_module, "telnetclean",
+                                  "Enable Automatic pre-processing of Telnet-encapsulated data to remove extra 0xFF (IAC) bytes",
+                                  "Whether the SEL Protocol dissector should automatically pre-process Telnet data to remove IAC bytes",
+                                  &cp2179_telnet_clean);
+
+
+}
+
+
+void
+proto_reg_handoff_cp2179(void)
+{
+   static int cp2179_prefs_initialized = FALSE;
+   static dissector_handle_t cp2179_handle;
+   static unsigned int cp2179_port;
+
+    if (!cp2179_prefs_initialized){
+        cp2179_handle = new_create_dissector_handle(dissect_cp2179, proto_cp2179);
+        cp2179_prefs_initialized = TRUE;
+    }
+     else {
+        dissector_delete_uint("tcp.port", cp2179_port, cp2179_handle);
+    }
+
+    cp2179_port = global_cp2179_tcp_port;
+
+    dissector_add_uint("tcp.port", cp2179_port, cp2179_handle);
+}
+
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
index fea831cbb11aa3f196ce3d4a3060a59aafc006a4..14bd1b58d578498dd6088f85f4267230e8bd483a 100644 (file)
@@ -93,6 +93,7 @@ static dissector_handle_t dnp3_handle;
 static dissector_handle_t modbus_handle;
 static dissector_handle_t synphasor_handle;
 static dissector_handle_t lg8979_handle;
+static dissector_handle_t cp2179_handle;
 
 #define RTACSER_HEADER_LEN    12
 
@@ -112,6 +113,7 @@ static dissector_handle_t lg8979_handle;
 #define RTACSER_PAYLOAD_MODBUS      3
 #define RTACSER_PAYLOAD_SYNPHASOR   4
 #define RTACSER_PAYLOAD_LG8979      5
+#define RTACSER_PAYLOAD_CP2179      6
 
 /* Event Types */
 static const value_string rtacser_eventtype_vals[] = {
@@ -136,6 +138,7 @@ static const enum_val_t rtacser_payload_proto_type[] = {
   { "MODBUS RTU", "MODBUS RTU",  RTACSER_PAYLOAD_MODBUS     },
   { "SYNPHASOR ", "SYNPHASOR ",  RTACSER_PAYLOAD_SYNPHASOR  },
   { "L&G 8979  ", "L&G 8979  ",  RTACSER_PAYLOAD_LG8979     },
+  { "CP 2179   ", "CP 2179   ",  RTACSER_PAYLOAD_CP2179     },
   { NULL, NULL, 0 }
 };
 
@@ -258,6 +261,10 @@ dissect_rtacser_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                 payload_tvb = tvb_new_subset_remaining(tvb, RTACSER_HEADER_LEN);
                 call_dissector(lg8979_handle, payload_tvb, pinfo, tree);
                 break;
+            case RTACSER_PAYLOAD_CP2179:
+                payload_tvb = tvb_new_subset_remaining(tvb, RTACSER_HEADER_LEN);
+                call_dissector(cp2179_handle, payload_tvb, pinfo, tree);
+                break;
             default:
                 break;
         }
@@ -377,6 +384,7 @@ proto_reg_handoff_rtacser(void)
     modbus_handle = find_dissector("mbrtu");
     synphasor_handle = find_dissector("synphasor");
     lg8979_handle = find_dissector("lg8979");
+    cp2179_handle = find_dissector("cp2179");
 
     dissector_add_uint("wtap_encap", WTAP_ENCAP_RTAC_SERIAL, rtacser_handle);
 }