From Martin Renold via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5730
authoralagoutte <alagoutte@f5534014-38df-0310-8fa8-9805f1628bb7>
Mon, 31 Oct 2011 18:37:58 +0000 (18:37 +0000)
committeralagoutte <alagoutte@f5534014-38df-0310-8fa8-9805f1628bb7>
Mon, 31 Oct 2011 18:37:58 +0000 (18:37 +0000)
Dissector for HSR and PRP-1

Here is a patch that adds a dissector for HSR and for PRP-1. Both protocols are defined in IEC62439 Part 3. (High-availability Seamless Redundancy / Parallel Redundancy Protocol)

The existing PRP dissector has been refactored to support both the old PRP (now called PRP-0) and the new PRP-1.

There are three distinct dissectors:
- HSR (ethertype 892F)
- HSR/PRP supervision (ethertype 88FB)
- PRP-0 and PRP-1 (trailer dissector; disabled by default)

From me :
* Fix Clang Warning
* Add modification for CMakeLists.txt

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@39692 f5534014-38df-0310-8fa8-9805f1628bb7

AUTHORS
epan/CMakeLists.txt
epan/dissectors/Makefile.common
epan/dissectors/packet-ethertype.c
epan/dissectors/packet-hsr-prp-supervision.c [new file with mode: 0644]
epan/dissectors/packet-hsr.c [new file with mode: 0644]
epan/dissectors/packet-prp.c
epan/etypes.h

diff --git a/AUTHORS b/AUTHORS
index 7f4b56d..f39834b 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -3333,7 +3333,12 @@ Spenser Sheng           <spenser.sheng [AT] ericsson.com> {
 Benjamin Stocks                <bmstocks [AT] ra.rockwell.com> {
        CIP Motion dissector
 }
-
+Florian Reichert       <refl [AT] zhaw.ch> {
+       HSR and PRP-1 dissector
+}
+Martin Renold          <reld [AT] zhaw.ch> {
+       HSR and PRP-1 dissector
+}
 
 and by:
 
index 477cf91..296fe20 100644 (file)
@@ -639,6 +639,8 @@ set(DISSECTOR_SRC
        dissectors/packet-hpext.c
        dissectors/packet-hpsw.c
        dissectors/packet-hpteam.c
+       dissectors/packet-hsr.c
+       dissectors/packet-packet-hsr-prp-supervision.c
        dissectors/packet-hsrp.c
        dissectors/packet-http.c
        dissectors/packet-hyperscsi.c
index 347894e..b8a6918 100644 (file)
@@ -560,6 +560,8 @@ DISSECTOR_SRC = \
        packet-hpext.c          \
        packet-hpsw.c           \
        packet-hpteam.c         \
+       packet-hsr.c            \
+       packet-hsr-prp-supervision.c            \
        packet-hsrp.c           \
        packet-http.c           \
        packet-hyperscsi.c      \
index ed535b9..c82a184 100644 (file)
@@ -162,11 +162,12 @@ const value_string etype_vals[] = {
   { ETHERTYPE_LINX, "LINX IPC Protocol" },
   { ETHERTYPE_FIP, "FCoE Initialization Protocol" },
   { ETHERTYPE_PTP, "PTPv2 over Ethernet (IEEE1588)" },
-  { ETHERTYPE_PRP, "Parallel Redundancy Protocol (IEC62439 Chapter 6)" },
+  { ETHERTYPE_PRP, "Parallel Redundancy Protocol (PRP) and HSR Supervision (IEC62439 Part 3)" },
   { ETHERTYPE_FLIP, "Flow Layer Internal Protocol" },
   { ETHERTYPE_ROCE, "RDMA over Converged Ethernet" },
   { ETHERTYPE_TDMOE, "Digium TDM over Ethernet Protocol" },
   { ETHERTYPE_WAI, "WAI Authentication Protocol" },
+  { ETHERTYPE_HSR, "High-availability Seamless Redundancy (IEC62439 Part 3)" },
   { 0, NULL }
 };
 
diff --git a/epan/dissectors/packet-hsr-prp-supervision.c b/epan/dissectors/packet-hsr-prp-supervision.c
new file mode 100644 (file)
index 0000000..6388f93
--- /dev/null
@@ -0,0 +1,263 @@
+/* packet-hsr-prp-supervision.c
+ * Routines for HSR/PRP supervision dissection (IEC62439 Part 3)
+ * Copyright 2009, Florian Reichert <refl[AT]zhaw.ch>
+ * Copyright 2011, Martin Renold <reld[AT]zhaw.ch>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald[AT]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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <glib.h>
+#include <epan/packet.h>
+#include <epan/etypes.h>
+
+/**********************************************************/
+/* Channel values for the supervision type field          */
+/**********************************************************/
+
+static const value_string type_vals[] = {
+  {20, "PRP Node (Duplicate Discard)"},
+  {21, "PRP Node (Duplicate Accept)"},
+  {22, "Obsolete TLV value"},
+  {23, "HSR Node"},
+  {30, "Redundancy Box MAC Address"},
+  {31, "Virtual Dual Attached Node"},
+  {0,  "End of TLVs"},
+  {0,  NULL}
+};
+
+/**********************************************************/
+/* Initialize the protocol and registered fields          */
+/**********************************************************/
+
+static int proto_hsr_prp_supervision = -1;
+
+/* Initialize supervision frame fields */
+static int hf_hsr_prp_supervision_path = -1;
+static int hf_hsr_prp_supervision_version = -1;
+static int hf_hsr_prp_supervision_seqno = -1;
+static int hf_hsr_prp_supervision_tlv_type = -1;
+static int hf_hsr_prp_supervision_tlv_length = -1;
+static int hf_hsr_prp_supervision_source_mac_address_A = -1;
+static int hf_hsr_prp_supervision_source_mac_address_B = -1;
+static int hf_hsr_prp_supervision_source_mac_address = -1;
+static int hf_hsr_prp_supervision_red_box_mac_address = -1;
+static int hf_hsr_prp_supervision_vdan_mac_address = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_hsr_prp_supervision = -1;
+
+/* Code to actually dissect the packets */
+static void
+dissect_hsr_prp_supervision(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+    proto_item *ti;
+    proto_tree *hsr_prp_supervision_tree;
+    guint8 tlv_type;
+    guint8 tlv_length;
+    guint16 sup_version;
+    int offset;
+
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "HSR/PRP");
+
+    /* may get modified later while parsing */
+    col_set_str(pinfo->cinfo, COL_INFO, "HSR or PRP Supervision");
+
+    /* create display subtree for the protocol */
+    ti = proto_tree_add_item(tree, proto_hsr_prp_supervision, tvb, 0, -1, ENC_NA);
+
+    hsr_prp_supervision_tree = proto_item_add_subtree(ti, ett_hsr_prp_supervision);
+
+    offset = 0;
+
+    /* SupVersion */
+    proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_path,
+                        tvb, offset, 2, ENC_BIG_ENDIAN);
+    proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_version,
+                        tvb, offset, 2, ENC_BIG_ENDIAN);
+    sup_version = tvb_get_ntohs(tvb, 0) & 0x0fff;
+    offset += 2;
+
+    if (sup_version > 0) {
+        /* SupSequenceNumber */
+        proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_seqno,
+                            tvb, offset, 2, ENC_BIG_ENDIAN);
+        offset += 2;
+    }
+
+    while (tvb_reported_length_remaining(tvb, offset)) {
+        /* TLV.type */
+        tlv_type = tvb_get_guint8(tvb, offset);
+        proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_tlv_type,
+                            tvb, offset, 1, ENC_BIG_ENDIAN);
+        offset += 1;
+
+        /* TLV.length */
+        tlv_length = tvb_get_guint8(tvb, offset);
+        proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_tlv_length,
+                            tvb, offset, 1, ENC_BIG_ENDIAN);
+        offset += 1;
+
+        /* TLV.value */
+        if ((tlv_type == 20 || tlv_type == 21 || tlv_type == 23) && (tlv_length == 6 || tlv_length == 12)) {
+            if (tlv_type == 23) {
+                col_set_str(pinfo->cinfo, COL_INFO, "HSR Supervision");
+            } else {
+                col_set_str(pinfo->cinfo, COL_INFO, "PRP Supervision");
+            }
+            if (tlv_length == 12) {
+                /* MacAddressA, MacAddressB (PRP only) */
+                proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address_A,
+                                    tvb, offset, 6, ENC_NA);
+                proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address_B,
+                                    tvb, offset+6, 6, ENC_NA);
+                /* PRP-0 supervision: if the node is not a RedBox, we have
+                   just read the last TLV. The next two octets are
+                   required to be zero by PRP-0. We will dissect those as
+                   "end of list" and break. */
+            } else {
+                /* MacAddress */
+                proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_source_mac_address,
+                                    tvb, offset, 6, ENC_NA);
+            }
+        } else if (tlv_type == 30 && tlv_length == 6) {
+            /* RedBoxMacAddress */
+            proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_red_box_mac_address,
+                                tvb, offset, 6, ENC_NA);
+            if (sup_version == 0) {
+                /* PRP-0 supervision: end of TLV data. Stop now, don't
+                   interpret the padding. */
+                offset += tlv_length;
+                break;
+            }
+        } else if (tlv_type == 31 && tlv_length == 6) {
+            /* VdanMacAddress */
+            proto_tree_add_item(hsr_prp_supervision_tree, hf_hsr_prp_supervision_vdan_mac_address,
+                                tvb, offset, 6, ENC_NA);
+            if (sup_version == 0) {
+                /* PRP-0 supervision: end of TLV data, padding starts */
+                offset += tlv_length;
+                break;
+            }
+        } else if (tlv_type == 0) {
+            /* End of TLV list. */
+            offset += tlv_length;
+            break;
+        } else {
+            /* unknown TLV.type, or unexpected TLV.length */
+        }
+        offset += tlv_length;
+    }
+
+    proto_item_set_len(ti, offset);
+    /* Adjust the length of this tvbuff to include only the supervision data.
+       This allows the rest to be marked as padding. */
+    tvb_set_reported_length(tvb, offset);
+}
+
+
+/* Register the protocol with Wireshark */
+void proto_register_hsr_prp_supervision(void)
+{
+
+    static hf_register_info hf[] = {
+
+        { &hf_hsr_prp_supervision_path,
+            { "Path", "hsr_prp_supervision.path",
+            FT_UINT16, BASE_DEC, NULL, 0xf000,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_version,
+            { "Version", "hsr_prp_supervision.version",
+            FT_UINT16, BASE_DEC, NULL, 0x0fff,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_seqno,
+            { "Sequence number", "hsr_prp_supervision.supervision_seqno",
+            FT_UINT16, BASE_DEC, NULL, 0x00,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_tlv_type,
+            { "TLV type", "hsr_prp_supervision.tlv.type",
+            FT_UINT8, BASE_DEC, VALS(type_vals), 0x00,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_tlv_length,
+            { "TLV length", "hsr_prp_supervision.tlv.length",
+            FT_UINT8, BASE_DEC, NULL, 0x00,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_source_mac_address_A,
+            { "Source MAC Address A", "hsr_prp_supervision.source_mac_address_A",
+            FT_ETHER, BASE_NONE, NULL, 0x00,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_source_mac_address_B,
+            { "Source MAC Address B", "hsr_prp_supervision.source_mac_address_B",
+            FT_ETHER, BASE_NONE, NULL, 0x00,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_source_mac_address,
+            { "Source MAC Address", "hsr_prp_supervision.source_mac_address",
+            FT_ETHER, BASE_NONE, NULL, 0x00,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_red_box_mac_address,
+            { "RedBox MAC Address", "hsr_prp_supervision.red_box_mac_address",
+            FT_ETHER, BASE_NONE, NULL, 0x00,
+            NULL, HFILL }
+        },
+        { &hf_hsr_prp_supervision_vdan_mac_address,
+            { "VDAN MAC Address", "hsr_prp_supervision.vdan_mac_address",
+            FT_ETHER, BASE_NONE, NULL, 0x00,
+            NULL, HFILL }
+        }
+    };
+
+
+    static gint *ett[] = {
+        &ett_hsr_prp_supervision
+    };
+
+    /* Register the protocol name and description */
+    proto_hsr_prp_supervision = proto_register_protocol("HSR/PRP Supervision (IEC62439 Part 3)",
+                        "HSR_PRP_SUPERVISION", "hsr_prp_supervision");
+
+
+    /* Required function calls to register the header fields and subtree used */
+    proto_register_field_array(proto_hsr_prp_supervision, hf, array_length(hf));
+    proto_register_subtree_array(ett, array_length(ett));
+
+
+
+}
+
+
+void proto_reg_handoff_hsr_prp_supervision(void)
+{
+    dissector_handle_t hsr_prp_supervision_handle;
+    hsr_prp_supervision_handle = create_dissector_handle(dissect_hsr_prp_supervision, proto_hsr_prp_supervision);
+    dissector_add_uint("ethertype", ETHERTYPE_PRP, hsr_prp_supervision_handle);
+}
diff --git a/epan/dissectors/packet-hsr.c b/epan/dissectors/packet-hsr.c
new file mode 100644 (file)
index 0000000..490cc21
--- /dev/null
@@ -0,0 +1,201 @@
+/* packet-hsr.c
+ * Routines for HSR dissection (IEC62439 Part 3)
+ * Copyright 2009, Florian Reichert <refl[AT]zhaw.ch>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald[AT]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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+#include <epan/etypes.h>
+
+/**********************************************************/
+/* Lengths of fields within a HSR packet.                 */
+/**********************************************************/
+#define HSR_LSDU_PATH_LENGTH                 2
+#define HSR_SEQUENZNR_LENGTH                 2
+
+#define HSR_TOTAL_LENGTH                     4
+
+/**********************************************************/
+/* Offsets of fields within a HSR packet.                 */
+/**********************************************************/
+#define HSR_PATH_OFFSET                      0
+#define HSR_SEQUENZNR_OFFSET                 2
+
+static const value_string hsr_laneid_vals[] = {
+    {0, "Lane A"},
+    {1, "Lane B"},
+    {0, NULL}
+};
+
+/**********************************************************/
+/* Initialize the protocol and registered fields          */
+/**********************************************************/
+
+static int proto_hsr = -1;
+
+/* Initialize supervision frame fields */
+
+
+static int hf_hsr_path = -1;
+static int hf_hsr_netid = -1;
+static int hf_hsr_laneid = -1;
+static int hf_hsr_lsdu_size = -1;
+static int hf_hsr_sequence_nr = -1;
+static int hf_type= -1;
+
+static dissector_table_t ethertype_subdissector_table;
+/* Initialize the subtree pointers */
+static gint ett_hsr_frame = -1;
+
+static dissector_handle_t data_handle;
+
+/* Code to actually dissect the packets */
+static  void
+dissect_hsr_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+    proto_item *ti;
+    proto_tree *hsr_tree;
+    tvbuff_t *next_tvb;
+    guint16 etype;
+    guint16 lsdu_size, lsdu_size_correct;
+
+    if (check_col(pinfo->cinfo, COL_PROTOCOL))
+        col_set_str(pinfo->cinfo, COL_PROTOCOL, "HSR");
+
+    if (check_col(pinfo->cinfo, COL_INFO)){
+        col_set_str(pinfo->cinfo, COL_INFO, "HSR-Data Frame");
+    }
+
+    /* create display subtree for the protocol */
+
+    ti = proto_tree_add_item(tree, proto_hsr, tvb, 0, HSR_TOTAL_LENGTH, ENC_NA);
+
+    hsr_tree = proto_item_add_subtree(ti, ett_hsr_frame);
+
+    proto_tree_add_item(hsr_tree, hf_hsr_path,
+                        tvb, HSR_PATH_OFFSET, HSR_LSDU_PATH_LENGTH , ENC_BIG_ENDIAN);
+
+    proto_tree_add_item(hsr_tree, hf_hsr_netid,
+                        tvb, HSR_PATH_OFFSET, HSR_LSDU_PATH_LENGTH , ENC_BIG_ENDIAN);
+
+    proto_tree_add_item(hsr_tree, hf_hsr_laneid,
+                        tvb, HSR_PATH_OFFSET, HSR_LSDU_PATH_LENGTH , ENC_BIG_ENDIAN);
+
+
+    lsdu_size = tvb_get_ntohs(tvb, HSR_PATH_OFFSET) & 0x0fff;
+    lsdu_size_correct = tvb_reported_length_remaining(tvb, 0);
+    if (lsdu_size == lsdu_size_correct) {
+        proto_tree_add_uint_format(hsr_tree, hf_hsr_lsdu_size,
+                                   tvb, HSR_PATH_OFFSET, HSR_LSDU_PATH_LENGTH, lsdu_size,
+                                   "LSDU size: %d [correct]", lsdu_size);
+    } else {
+        proto_tree_add_uint_format(hsr_tree, hf_hsr_lsdu_size,
+                                   tvb, HSR_PATH_OFFSET, HSR_LSDU_PATH_LENGTH, lsdu_size,
+                                   "LSDU size: %d [WRONG, should be %d]", lsdu_size, lsdu_size_correct);
+    }
+
+    proto_tree_add_item(hsr_tree, hf_hsr_sequence_nr,
+                        tvb, HSR_SEQUENZNR_OFFSET,HSR_SEQUENZNR_LENGTH, ENC_BIG_ENDIAN);
+
+    proto_tree_add_item(hsr_tree, hf_type,
+                        tvb, HSR_TOTAL_LENGTH,2, ENC_BIG_ENDIAN);
+
+    next_tvb = tvb_new_subset (tvb, HSR_TOTAL_LENGTH + 2, -1, -1);
+
+    etype = tvb_get_ntohs(tvb, HSR_TOTAL_LENGTH);
+
+    if (!dissector_try_uint(ethertype_subdissector_table, etype, next_tvb, pinfo, tree))
+        call_dissector(data_handle, next_tvb, pinfo, hsr_tree);
+
+}
+
+
+
+/* Register the protocol with Wireshark */
+void proto_register_hsr(void)
+{
+    static hf_register_info hf[] = {
+        { &hf_hsr_path,
+          { "Path", "hsr.path",
+            FT_UINT16, BASE_DEC, NULL, 0xf000,
+            NULL, HFILL }
+        },
+
+        { &hf_hsr_netid,
+          { "Network id", "hsr.netid",
+            FT_UINT16, BASE_DEC, NULL, 0xe000,
+            NULL, HFILL }
+        },
+
+        { &hf_hsr_laneid,
+          { "Lane id", "hsr.laneid",
+            FT_UINT16, BASE_DEC, VALS(hsr_laneid_vals), 0x1000,
+            NULL, HFILL }
+        },
+
+        { &hf_hsr_lsdu_size,
+          { "LSDU size", "hsr.lsdu_size",
+            FT_UINT16, BASE_DEC, NULL, 0x0fff,
+            NULL, HFILL }
+        },
+
+        { &hf_hsr_sequence_nr,
+          { "Sequence number", "hsr.hsr_sequence_nr",
+            FT_UINT16, BASE_DEC, NULL, 0x00,
+            NULL, HFILL }
+        },
+        { &hf_type,
+          { "Type", "hsr.type",
+            FT_UINT16, BASE_HEX, VALS(etype_vals), 0x00,
+            NULL, HFILL }
+        }
+
+    };
+
+    static gint *ett[] = {
+        &ett_hsr_frame,
+    };
+
+    /* Register the protocol name and description */
+    proto_hsr = proto_register_protocol("High-availability Seamless Redundancy (IEC62439 Part 3 Chapter 5)",
+                                        "HSR", "hsr");
+
+    /* Required function calls to register the header fields and subtree used */
+    proto_register_field_array(proto_hsr, hf, array_length(hf));
+    proto_register_subtree_array(ett, array_length(ett));
+}
+
+
+void proto_reg_handoff_hsr(void)
+{
+    dissector_handle_t hsr_frame_handle;
+    hsr_frame_handle = create_dissector_handle(dissect_hsr_frame, proto_hsr);
+    dissector_add_uint("ethertype", ETHERTYPE_HSR, hsr_frame_handle);
+
+    ethertype_subdissector_table = find_dissector_table("ethertype");
+    data_handle = find_dissector("data");
+}
index bf24f5a..7f5a65f 100644 (file)
@@ -1,14 +1,11 @@
 /* packet-prp.c
  * Routines for PRP (Parallel Redundancy Protocol; IEC62439 Part 3) dissection
  * Copyright 2007, Sven Meier <msv[AT]zhwin.ch>
+ * Copyright 2011, Martin Renold <reld[AT]zhaw.ch>
+ * Copyright 2011, Florian Reichert <refl [AT] zhaw.ch>
  *
  * $Id$
  *
- * Revisions:
- * -
- *
- * A plugin for:
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald[AT]wireshark.org>
  * Copyright 1998 Gerald Combs
 # include "config.h"
 #endif
 
-#include <stdlib.h>
 #include <glib.h>
 #include <epan/packet.h>
 #include <epan/etypes.h>
 #include <epan/prefs.h>
 
-/**********************************************************/
-/* Offsets of fields within a PRP packet.          */
-/**********************************************************/
-#define    PRP_VERSION_OFFSET                      0
-#define    PRP_TYPE_OFFSET                         2
-#define    PRP_LENGTH_OFFSET                       3
-#define    PRP_SOURCEMACADDRESSA_OFFSET            4
-#define    PRP_SOURCEMACADDRESSB_OFFSET            10
-#define    PRP_TYPE2_OFFSET                        16
-#define    PRP_LENGTH2_OFFSET                      17
-#define    PRP_REDBOXVDANMACADDRESS_OFFSET         18
-
-/**********************************************************/
-/* Lengths of fields within a PRP packet.          */
-/**********************************************************/
-#define    PRP_VERSION_LENGTH                      2
-#define    PRP_TYPE_LENGTH                         1
-#define    PRP_LENGTH_LENGTH                       1
-#define    PRP_SOURCE_LENGTH                       6
-#define    PRP_TOTAL_LENGTH                        24
-
-/**********************************************************/
-/* Channel values for the PRP_TYPE field          */
-/**********************************************************/
-#define    PRP_TYPE_DUPLICATE_ACCEPT               21
-#define    PRP_TYPE_DUPLICATE_DISCARD              20
-#define    PRP_TYPE_REDBOX                         30
-#define    PRP_TYPE_VDAN                           31
-
-static const value_string prp_type_vals[] = {
-  {PRP_TYPE_DUPLICATE_ACCEPT,     "Duplicate Accept"},
-  {PRP_TYPE_DUPLICATE_DISCARD,    "Duplicate Discard"},
-  {PRP_TYPE_REDBOX,               "Redundancy Box"},
-  {PRP_TYPE_VDAN,                 "Virtual Dual Attached Node"},
-  {0,                NULL          } };
-
-
 #define    PRP_LAN_A                               10
 #define    PRP_LAN_B                               11
 
 static const value_string prp_lan_vals[] = {
-  {PRP_LAN_A,    "LAN A"},
-  {PRP_LAN_B,    "LAN B"},
-  {0,        NULL } };
+    {PRP_LAN_A, "LAN A"},
+    {PRP_LAN_B, "LAN B"},
+    {0, NULL}
+};
 
 /**********************************************************/
 /* Initialize the protocol and registered fields      */
@@ -91,25 +51,16 @@ void proto_reg_handoff_prp(void);
 static int proto_prp = -1;
 static module_t *prp_module;
 
-/* Initialize supervision frame fields */
-static int hf_prp_supervision_frame_version = -1;
-static int hf_prp_supervision_frame_type = -1;
-static int hf_prp_supervision_frame_length = -1;
-static int hf_prp_supervision_frame_source_mac_address_A = -1;
-static int hf_prp_supervision_frame_source_mac_address_B = -1;
-static int hf_prp_supervision_frame_type2 = -1;
-static int hf_prp_supervision_frame_length2 = -1;
-static int hf_prp_supervision_frame_red_box_mac_address = -1;
-static int hf_prp_supervision_frame_vdan_mac_address = -1;
 
 /* Initialize trailer fields */
 static int hf_prp_redundancy_control_trailer_sequence_nr = -1;
 static int hf_prp_redundancy_control_trailer_lan = -1;
 static int hf_prp_redundancy_control_trailer_size = -1;
+static int hf_prp_redundancy_control_trailer_suffix = -1;
+static int hf_prp_redundancy_control_trailer_version = -1;
 
 
 /* Initialize the subtree pointers */
-static gint ett_prp_supervision_frame = -1;
 static gint ett_prp_redundancy_control_trailer = -1;
 
 
@@ -125,70 +76,6 @@ static gboolean prp_enable_dissector = FALSE;
 
 
 /* Code to actually dissect the packets */
-static void
-dissect_prp_supervision_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
-{
-    proto_item *ti;
-    proto_tree *prp_tree;
-    guint16 tlv2;
-
-    col_set_str(pinfo->cinfo, COL_PROTOCOL, "PRP");
-
-    col_set_str(pinfo->cinfo, COL_INFO, "Supervision Frame");
-
-    if (!tree)
-        return;
-
-    /* create display subtree for the protocol */
-    ti = proto_tree_add_item(tree, proto_prp, tvb, 0, PRP_TOTAL_LENGTH,
-                 ENC_NA);
-
-    prp_tree = proto_item_add_subtree(ti, ett_prp_supervision_frame);
-
-    proto_tree_add_item(prp_tree, hf_prp_supervision_frame_version,
-                        tvb, PRP_VERSION_OFFSET, PRP_VERSION_LENGTH, ENC_BIG_ENDIAN);
-
-    proto_tree_add_item(prp_tree, hf_prp_supervision_frame_type,
-                        tvb, PRP_TYPE_OFFSET, PRP_TYPE_LENGTH, ENC_BIG_ENDIAN);
-
-    proto_tree_add_item(prp_tree, hf_prp_supervision_frame_length,
-                        tvb, PRP_LENGTH_OFFSET, PRP_LENGTH_LENGTH, ENC_BIG_ENDIAN);
-
-    proto_tree_add_item(prp_tree, hf_prp_supervision_frame_source_mac_address_A,
-                        tvb, PRP_SOURCEMACADDRESSA_OFFSET, PRP_SOURCE_LENGTH,
-                       ENC_NA);
-
-    proto_tree_add_item(prp_tree, hf_prp_supervision_frame_source_mac_address_B,
-                        tvb, PRP_SOURCEMACADDRESSB_OFFSET, PRP_SOURCE_LENGTH,
-                        ENC_NA);
-
-
-    tlv2 = tvb_get_ntohs(tvb, PRP_TYPE2_OFFSET);
-
-    if((tlv2 == 0x1e06) || (tlv2 == 0x1f06))
-    {
-        proto_tree_add_item(prp_tree, hf_prp_supervision_frame_type2,
-                            tvb, PRP_TYPE2_OFFSET, PRP_TYPE_LENGTH, ENC_BIG_ENDIAN);
-
-        proto_tree_add_item(prp_tree, hf_prp_supervision_frame_length2,
-                            tvb, PRP_LENGTH2_OFFSET, PRP_LENGTH_LENGTH, ENC_BIG_ENDIAN);
-
-        if(tlv2 == 0x1e06)
-        {
-            proto_tree_add_item(prp_tree, hf_prp_supervision_frame_red_box_mac_address,
-                                tvb, PRP_REDBOXVDANMACADDRESS_OFFSET, PRP_SOURCE_LENGTH,
-                                ENC_NA);
-        }
-        else
-        {
-            proto_tree_add_item(prp_tree, hf_prp_supervision_frame_vdan_mac_address,
-                                tvb, PRP_REDBOXVDANMACADDRESS_OFFSET, PRP_SOURCE_LENGTH,
-                                ENC_NA);
-        }
-
-     }
-}
-
 static void
 dissect_prp_redundancy_control_trailer(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
 {
@@ -197,13 +84,17 @@ dissect_prp_redundancy_control_trailer(tvbuff_t *tvb, packet_info *pinfo _U_, pr
     guint i;
     guint length;
     guint offset;
-    guint16 lan_size;
-    guint trailer_offset;
+    guint16 lan_id;
+    guint16 lsdu_size;
+    guint16 prp1_suffix;
+    guint trailer_start;
+    guint trailer_length;
 
     if (!tree)
         return;
 
-    trailer_offset = 0;
+    trailer_start = 0;
+    trailer_length = 0;
     length = tvb_reported_length(tvb);
 
     if(length < 14)
@@ -220,121 +111,126 @@ dissect_prp_redundancy_control_trailer(tvbuff_t *tvb, packet_info *pinfo _U_, pr
         offset = 14;
     }
 
-    if(length <= 64)
+    /* search for PRP-0 trailer */
+    /* If the frame is >  64 bytes, the PRP-0 trailer is always at the end. */
+    /* If the frame is <= 64 bytes, the PRP-0 trailer may be anywhere (before the padding) */
+    for(i=length-4; i>=offset; i--)
     {
-        for(i=length; i>=(offset+4); i--)  /* search trailer */
+        lan_id    = tvb_get_ntohs(tvb, (i+2)) >> 12;
+        lsdu_size = tvb_get_ntohs(tvb, (i+2)) & 0x0fff;
+        if(lsdu_size == i+4-offset && (lan_id == 0xa || lan_id == 0xb))
         {
-            lan_size = tvb_get_ntohs(tvb, (i-2));
-            if((lan_size == (0xa000 | ((i-offset) & 0x0fff)))
-               || (lan_size == (0xb000 | ((i-offset) & 0x0fff))))
-            {
-                trailer_offset = i;
-            }
+            trailer_start = i;
+            trailer_length = 4;
+            break;
+        }
+
+        if (length > 64) {
+            break; /* don't search, just check the last position */
         }
     }
-    else if(length > 64)
+
+    /* check for PRP-1 trailer */
+    /* PRP-1 trailer is always at the end of the frame, after any padding. */
     {
-        lan_size = tvb_get_ntohs(tvb, (length-2));
-        if((lan_size == (0xa000 | ((length-offset) & 0x0fff)))
-            || (lan_size == (0xb000 | ((length-offset) & 0x0fff))))
+        lan_id      = tvb_get_ntohs(tvb, length-4) >> 12;
+        lsdu_size   = tvb_get_ntohs(tvb, length-4) & 0x0fff;
+        prp1_suffix = tvb_get_ntohs(tvb, length-2);
+
+        if(prp1_suffix == ETHERTYPE_PRP && (lan_id == 0xa || lan_id == 0xb))
         {
-            trailer_offset = length;
+            /* We don't check the lsdu_size, we just display whether
+               it's correct. Helpful for testing, because different
+               definitions of the lsdu_size did exist. */
+            trailer_start = length-6;
+            trailer_length = 6;
         }
     }
 
-    if(trailer_offset != 0)
+    if(trailer_length != 0)
     {
         /* create display subtree for the protocol */
-        ti = proto_tree_add_item(tree, proto_prp, tvb, trailer_offset - 4,
-                     trailer_offset, ENC_NA);
+        ti = proto_tree_add_item(tree, proto_prp, tvb, trailer_start,
+                                 trailer_length, ENC_NA);
 
         prp_tree = proto_item_add_subtree(ti, ett_prp_redundancy_control_trailer);
 
+        if (trailer_length == 4) {
+            ti = proto_tree_add_string(prp_tree, hf_prp_redundancy_control_trailer_version,
+                                       tvb, trailer_start, trailer_length, "PRP-0");
+        } else {
+            ti = proto_tree_add_string(prp_tree, hf_prp_redundancy_control_trailer_version,
+                                       tvb, trailer_start, trailer_length, "PRP-1");
+        }
+        PROTO_ITEM_SET_GENERATED(ti);
+
         proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_sequence_nr,
-                            tvb, (trailer_offset-4), 2, ENC_BIG_ENDIAN);
+                            tvb, trailer_start, 2, ENC_BIG_ENDIAN);
 
         proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_lan,
-                            tvb, (trailer_offset-2), 2, ENC_BIG_ENDIAN);
-
-        proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_size,
-                            tvb, (trailer_offset-2), 2, ENC_BIG_ENDIAN);
+                            tvb, trailer_start+2, 2, ENC_BIG_ENDIAN);
+
+        if (trailer_length == 4) {
+            /* PRP-0 */
+            proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_size,
+                                tvb, trailer_start+2, 2, ENC_BIG_ENDIAN);
+        } else {
+            /* PRP-1 */
+            int lsdu_size_correct = length-offset;
+            if (lsdu_size == lsdu_size_correct) {
+                proto_tree_add_uint_format(prp_tree, hf_prp_redundancy_control_trailer_size,
+                                           tvb, trailer_start+2, 2, lsdu_size,
+                                           "LSDU size: %d [correct]", lsdu_size);
+            } else {
+                proto_tree_add_uint_format(prp_tree, hf_prp_redundancy_control_trailer_size,
+                                           tvb, trailer_start+2, 2, lsdu_size,
+                                           "LSDU size: %d [WRONG, should be %d]", lsdu_size, lsdu_size_correct);
+            }
+            /* suffix */
+            proto_tree_add_item(prp_tree, hf_prp_redundancy_control_trailer_suffix,
+                                tvb, trailer_start+4, 2, ENC_BIG_ENDIAN);
+        }
     }
 }
 
 /* Register the protocol with Wireshark */
 void proto_register_prp(void)
 {
-    static hf_register_info hf[] = {
-
-        /*supervision frame*/
-        { &hf_prp_supervision_frame_version,
-            { "version", "prp.supervision_frame.version",
-            FT_UINT16, BASE_DEC, NULL, 0x00,
-            NULL, HFILL }
-        },
-        { &hf_prp_supervision_frame_type,
-            { "type", "prp.supervision_frame.type",
-            FT_UINT8, BASE_DEC, VALS(prp_type_vals), 0x00,
-            NULL, HFILL }
-        },
-        { &hf_prp_supervision_frame_length,
-            { "length", "prp.supervision_frame.length",
-            FT_UINT8, BASE_DEC, NULL, 0x00,
-            NULL, HFILL }
-        },
-        { &hf_prp_supervision_frame_source_mac_address_A,
-            { "sourceMacAddressA", "prp.supervision_frame.prp_source_mac_address_A",
-            FT_ETHER, BASE_NONE, NULL, 0x00,
-            NULL, HFILL }
-        },
-        { &hf_prp_supervision_frame_source_mac_address_B,
-            { "sourceMacAddressB", "prp.supervision_frame.prp_source_mac_address_B",
-            FT_ETHER, BASE_NONE, NULL, 0x00,
-            NULL, HFILL }
-        },
-       { &hf_prp_supervision_frame_type2,
-            { "type2", "prp.supervision_frame.type2",
-            FT_UINT8, BASE_DEC, VALS(prp_type_vals), 0x00,
-            NULL, HFILL }
-        },
-        { &hf_prp_supervision_frame_length2,
-            { "length2", "prp.supervision_frame.length2",
-            FT_UINT8, BASE_DEC, NULL, 0x00,
-            NULL, HFILL }
-        },
-        { &hf_prp_supervision_frame_red_box_mac_address,
-            { "redBoxMacAddress", "prp.supervision_frame.prp_red_box_mac_address",
-            FT_ETHER, BASE_NONE, NULL, 0x00,
-            NULL, HFILL }
-        },
-        { &hf_prp_supervision_frame_vdan_mac_address,
-            { "vdanMacAddress", "prp.supervision_frame.prp_vdan_mac_address",
-            FT_ETHER, BASE_NONE, NULL, 0x00,
-            NULL, HFILL }
-        },
 
+    static hf_register_info hf[] = {
         /*trailer*/
         { &hf_prp_redundancy_control_trailer_sequence_nr,
-            { "sequenceNr", "prp.trailer.prp_sequence_nr",
+            { "Sequence number", "prp.trailer.prp_sequence_nr",
             FT_UINT16, BASE_DEC, NULL, 0x00,
             NULL, HFILL }
         },
 
         { &hf_prp_redundancy_control_trailer_lan,
-            { "lan", "prp.trailer.prp_lan",
+            { "LAN", "prp.trailer.prp_lan",
             FT_UINT16, BASE_DEC, VALS(prp_lan_vals), 0xf000,
             NULL, HFILL }
         },
 
         { &hf_prp_redundancy_control_trailer_size,
-            { "size", "prp.trailer.prp_size",
+            { "Size", "prp.trailer.prp_size",
             FT_UINT16, BASE_DEC, NULL, 0x0fff,
             NULL, HFILL }
+        },
+
+        { &hf_prp_redundancy_control_trailer_suffix,
+            { "Suffix", "prp.trailer.prp1_suffix",
+            FT_UINT16, BASE_HEX, NULL, 0x00,
+            NULL, HFILL }
+        },
+
+        { &hf_prp_redundancy_control_trailer_version,
+            { "PRP Version", "prp.trailer.version",
+            FT_STRING, BASE_NONE, NULL, 0x00,
+            NULL, HFILL }
         }
     };
 
     static gint *ett[] = {
-        &ett_prp_supervision_frame,
         &ett_prp_redundancy_control_trailer,
     };
 
@@ -359,12 +255,8 @@ void proto_reg_handoff_prp(void)
     static gboolean prefs_initialized = FALSE;
 
     if (!prefs_initialized) {
-        dissector_handle_t prp_supervision_frame_handle;
         dissector_handle_t prp_redundancy_control_trailer_handle;
 
-        prp_supervision_frame_handle = create_dissector_handle(dissect_prp_supervision_frame, proto_prp);
-        dissector_add_uint("ethertype", ETHERTYPE_PRP, prp_supervision_frame_handle);
-
         prp_redundancy_control_trailer_handle = create_dissector_handle(dissect_prp_redundancy_control_trailer, proto_prp);
         register_postdissector(prp_redundancy_control_trailer_handle);
 
index d004d4b..76312a9 100644 (file)
                                                                                /*  There are three types of application services */
 
 #ifndef ETHERTYPE_PRP
-#define ETHERTYPE_PRP                  0x88FB  /* Parallel Redundancy Protocol (IEC62439 Chapter 6) */
+#define ETHERTYPE_PRP                  0x88FB  /* Parallel Redundancy Protocol (IEC62439 Part 3) */
 #endif
 
 #ifndef ETHERTYPE_FLIP
 #define ETHERTYPE_TTE_PCF              0x891D  /* TTEthernet Protocol Control Frame */
 #endif
 
+#ifndef ETHERTYPE_HSR
+#define ETHERTYPE_HSR                  0x892F  /* High-availability Seamless Redundancy (IEC62439 Part 3) */
+#endif
+
 #ifndef ETHERTYPE_LOOP
 #define ETHERTYPE_LOOP                 0x9000  /* used for layer 2 testing (do i see my own frames on the wire) */
 #endif