---
 epan/CMakeLists.txt                |    1 
 epan/dissectors/Makefile.common    |    1 
 epan/dissectors/packet-canopen.c   |  503 +++++++++++++++++++++++++++++++++++++
 epan/dissectors/packet-socketcan.c |    8 
 4 files changed, 510 insertions(+), 3 deletions(-)

Index: b/epan/CMakeLists.txt
===================================================================
--- a/epan/CMakeLists.txt
+++ b/epan/CMakeLists.txt
@@ -383,6 +383,7 @@
 	dissectors/packet-bt-utp.c
 	dissectors/packet-bvlc.c
 	dissectors/packet-calcappprotocol.c
+	dissectors/packet-canopen.c
 	dissectors/packet-capwap.c
 	dissectors/packet-cast.c
 	dissectors/packet-catapult-dct2000.c
Index: b/epan/dissectors/Makefile.common
===================================================================
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -296,6 +296,7 @@
 	packet-bt-utp.c		\
 	packet-bvlc.c		\
 	packet-calcappprotocol.c  \
+	packet-canopen.c	\
 	packet-capwap.c		\
 	packet-cast.c		\
 	packet-catapult-dct2000.c \
Index: b/epan/dissectors/packet-canopen.c
===================================================================
--- /dev/null
+++ b/epan/dissectors/packet-canopen.c
@@ -0,0 +1,503 @@
+/* packet-canopen.c
+ * Routines for CANopen dissection
+ * Copyright 2011, Yegor Yefremov <yegorslists@googlemail.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from WHATEVER_FILE_YOU_USED (where "WHATEVER_FILE_YOU_USED"
+ * is a dissector file; if you just copied this from README.developer,
+ * don't bother with the "Copied from" - you don't even need to put
+ * in a "Copied from" if you copied an existing dissector, especially
+ * if the bulk of the code in the new dissector is your code)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if 0
+/* Include only as needed */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+
+/* IF PROTO exposes code to other dissectors, then it must be exported
+   in a header file. If not, a header file is not needed at all. */
+//#include "packet-canopen.h"
+
+/* Forward declaration we need below (if using proto_reg_handoff...
+   as a prefs callback)       */
+//void proto_reg_handoff_canopen(void);
+
+/* Initialize the protocol and registered fields */
+static int proto_canopen = -1;
+static int hf_canopen_cob_id = -1;
+static int hf_canopen_type = -1;
+static int hf_canopen_function_code = -1;
+static int hf_canopen_node_id = -1;
+static int hf_canopen_pdo_data = -1;
+static int hf_canopen_pdo_data_string = -1;
+static int hf_canopen_sdo_cmd = -1;
+static int hf_canopen_sdo_main_idx = -1;
+static int hf_canopen_sdo_sub_idx = -1;
+static int hf_canopen_sdo_data = -1;
+static int hf_canopen_em_err_code = -1;
+static int hf_canopen_em_err_reg = -1;
+static int hf_canopen_em_err_field = -1;
+static int hf_canopen_nmt_ctrl_cs = -1;
+static int hf_canopen_nmt_ctrl_node_id = -1;
+static int hf_canopen_nmt_guard_state = -1;
+
+/* Global sample preference ("controls" display of numbers) */
+static gboolean gPREF_HEX = FALSE;
+/* Global sample port pref */
+static guint gPORT_PREF = 1234;
+
+/* Initialize the subtree pointers */
+static gint ett_canopen = -1;
+
+/* broadcast messages */
+#define FC_NMT			0x0
+#define FC_SYNC			0x1
+#define FC_TIME_STAMP		0x2
+
+/* point-to-point messages */
+#define FC_EMERGENCY		0x1
+#define FC_PDO1_TX		0x3
+#define FC_PDO1_RX		0x4
+#define FC_PDO2_TX		0x5
+#define FC_PDO2_RX		0x6
+#define FC_PDO3_TX		0x7
+#define FC_PDO3_RX		0x8
+#define FC_PDO4_TX		0x9
+#define FC_PDO4_RX		0xA
+#define FC_DEFAULT_SDO_TX	0xB
+#define FC_DEFAULT_SDO_RX	0xC
+#define FC_NMT_ERR_CONTROL	0xE
+
+/* message types */
+#define MT_UNKNOWN			0
+#define MT_NMT_CTRL			1
+#define MT_SYNC				2
+#define MT_TIME_STAMP			3
+#define MT_EMERGENCY			4
+#define MT_PDO				5
+#define MT_SDO				6
+#define MT_NMT_GUARD			7
+
+/* PDO offsets */
+#define CO_PDO_DATA_OFFSET		8
+
+/* SDO offsets */
+#define CO_SDO_CMD_OFFSET		8
+#define CO_SDO_MAIN_IDX_OFFSET		9
+#define CO_SDO_MAIN_SUB_OFFSET		11
+#define CO_SDO_DATA_OFFSET		12
+
+/* EMERGENCY offsets */
+#define CO_EM_ERR_CODE_OFFSET		8
+#define CO_EM_ERR_REG_OFFSET		10
+#define CO_EM_ERR_FIELD_OFFSET		11
+
+/* NMT offsets */
+#define CO_NMT_CTRL_CS_OFFSET		8
+#define CO_NMT_CTRL_NODE_ID_OFFSET	9
+#define CO_NMT_GUARD_STATE_OFFSET	8
+
+/* NMT command specifiers */
+static const value_string nmt_ctrl_cs[] = {
+	{ 0x1, "Start remote node"},
+	{ 0x2, "Stop remote node"},
+	{ 0x80, "Enter pre-operational state"},
+	{ 0x81, "Reset node"},
+	{ 0x82, "Reset communication"},
+	{ 0, NULL}
+};
+
+/* NMT states */
+static const value_string nmt_guard_state[] = {
+	{ 0x0, "Initialising"},
+	{ 0x1, "Disconnected"},
+	{ 0x2, "Connecting"},
+	{ 0x3, "Preparing"},
+	{ 0x4, "Stopped"},
+	{ 0x5, "Operational"},
+	{ 0x7F, "Pre-operational"},
+	{ 0, NULL}
+};
+
+static void
+canopen_detect_msg_type(guint function_code, guint node_id, char *msg_type, guint *msg_type_id)
+{
+	switch(function_code)
+	{
+		case FC_NMT:
+			sprintf(msg_type, "NMT");
+			*msg_type_id = MT_NMT_CTRL;
+			break;
+		case FC_SYNC:
+			if (node_id <= 0x80)
+			{
+				sprintf(msg_type, "Sync");
+				*msg_type_id = MT_SYNC;
+			}
+			else
+			{
+				sprintf(msg_type, "EMERGENCY");
+				*msg_type_id = MT_EMERGENCY;
+			}
+			break;
+		case FC_TIME_STAMP:
+			sprintf(msg_type, "TIME STAMP");
+			*msg_type_id = MT_TIME_STAMP;
+			break;
+		case FC_PDO1_TX:
+			sprintf(msg_type, "PDO1 (tx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_PDO1_RX:
+			sprintf(msg_type, "PDO1 (rx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_PDO2_TX:
+			sprintf(msg_type, "PDO2 (tx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_PDO2_RX:
+			sprintf(msg_type, "PDO2 (rx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_PDO3_TX:
+			sprintf(msg_type, "PDO3 (tx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_PDO3_RX:
+			sprintf(msg_type, "PDO3 (rx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_PDO4_TX:
+			sprintf(msg_type, "PDO4 (tx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_PDO4_RX:
+			sprintf(msg_type, "PDO4 (rx)");
+			*msg_type_id = MT_PDO;
+			break;
+		case FC_DEFAULT_SDO_TX:
+			sprintf(msg_type, "Default-SDO (tx)");
+			*msg_type_id = MT_SDO;
+			break;
+		case FC_DEFAULT_SDO_RX:
+			sprintf(msg_type, "Default-SDO (rx)");
+			*msg_type_id = MT_SDO;
+			break;
+		case FC_NMT_ERR_CONTROL:
+			sprintf(msg_type, "NMT Error Control");
+			*msg_type_id = MT_NMT_GUARD;
+			break;
+		default:
+			sprintf(msg_type, "unknown");
+			*msg_type_id = MT_UNKNOWN;
+			break;
+	}
+}
+
+/* Code to actually dissect the packets */
+static void
+dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+        proto_item *ti, *temp_ti, *cob_ti, *type_ti;
+        proto_tree *canopen_tree = NULL;
+        proto_tree *canopen_cob_tree = NULL;
+        proto_tree *canopen_type_tree = NULL;
+	guint function_code = -1;
+	guint node_id = -1;
+	guint32 id = -1;
+	guint msg_type_id = -1;
+	guint8 *bytes_data, can_data_len;
+	char co_buf[128], type_buf[128];
+
+	can_data_len = tvb_get_guint8(tvb, 4);
+	id = tvb_get_ntohl(tvb, 0);
+
+	node_id = (guint)(id & 0x7F);
+	function_code = (guint)((id >> 7) & 0xF);
+
+        if (tvb_length(tvb) < 1)
+                return 0;
+
+        col_set_str(pinfo->cinfo, COL_PROTOCOL, "CANopen");
+	col_clear(pinfo->cinfo, COL_INFO);
+	canopen_detect_msg_type(function_code, node_id, type_buf, &msg_type_id);
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s", type_buf);
+
+        if (tree) {
+
+                ti = proto_tree_add_item(tree, proto_canopen, tvb, 0, 1, FALSE);
+
+                canopen_tree = proto_item_add_subtree(ti, ett_canopen);
+
+		/* add COB-ID with function code and node id */
+		cob_ti = proto_tree_add_string(canopen_tree, hf_canopen_cob_id, tvb, 0, 4, "");
+                canopen_cob_tree = proto_item_add_subtree(cob_ti, ett_canopen);
+
+		/* add function code */
+                proto_tree_add_item(canopen_cob_tree,
+                    hf_canopen_function_code, tvb, 0, 4, FALSE);
+
+		/* add node id */
+                proto_tree_add_item(canopen_cob_tree,
+                    hf_canopen_node_id, tvb, 0, 4, FALSE);
+
+		/* add CANopen frame type */
+		type_ti = proto_tree_add_string(canopen_tree, hf_canopen_type, tvb, 0, 4, type_buf);
+                canopen_type_tree = proto_item_add_subtree(type_ti, ett_canopen);
+
+		switch(msg_type_id)
+		{
+			case MT_NMT_CTRL:
+				proto_tree_add_item(canopen_type_tree,
+					hf_canopen_nmt_ctrl_cs, tvb, CO_NMT_CTRL_CS_OFFSET, 1, FALSE);
+
+				proto_tree_add_item(canopen_type_tree,
+					hf_canopen_nmt_ctrl_node_id, tvb, CO_NMT_CTRL_NODE_ID_OFFSET, 1, FALSE);
+				break;
+			case MT_NMT_GUARD:
+				proto_tree_add_item(canopen_type_tree,
+					hf_canopen_nmt_guard_state, tvb, CO_NMT_GUARD_STATE_OFFSET, 1, FALSE);
+				break;
+			case MT_SYNC:
+				break;
+			case MT_TIME_STAMP:
+				break;
+			case MT_EMERGENCY:
+				proto_tree_add_item(canopen_type_tree,
+				    hf_canopen_em_err_code, tvb, CO_EM_ERR_CODE_OFFSET, 2, FALSE);
+
+				proto_tree_add_item(canopen_type_tree,
+				    hf_canopen_em_err_reg, tvb, CO_EM_ERR_REG_OFFSET, 1, FALSE);
+
+            			bytes_data = tvb_memdup(tvb, CO_EM_ERR_FIELD_OFFSET, 5);
+				proto_tree_add_bytes(canopen_type_tree,
+				    hf_canopen_em_err_field, tvb, CO_EM_ERR_FIELD_OFFSET, 4, bytes_data);
+				break;
+			case MT_PDO:
+				if(can_data_len)
+				{
+					bytes_data = tvb_memdup(tvb, CO_PDO_DATA_OFFSET, can_data_len);
+					proto_tree_add_bytes(canopen_type_tree,
+					    hf_canopen_pdo_data, tvb, CO_PDO_DATA_OFFSET, can_data_len, bytes_data);
+				}
+				else
+				{
+					proto_tree_add_string(canopen_type_tree, hf_canopen_pdo_data_string, tvb, CO_PDO_DATA_OFFSET, 0, "empty");
+				}
+				break;
+			case MT_SDO:
+				proto_tree_add_item(canopen_type_tree,
+				    hf_canopen_sdo_cmd, tvb, CO_SDO_CMD_OFFSET, 1, FALSE);
+
+				proto_tree_add_item(canopen_type_tree,
+				    hf_canopen_sdo_main_idx, tvb, CO_SDO_MAIN_IDX_OFFSET, 2, FALSE);
+
+				proto_tree_add_item(canopen_type_tree,
+				    hf_canopen_sdo_sub_idx, tvb, CO_SDO_MAIN_SUB_OFFSET, 1, FALSE);
+
+				/* TODO calculate actuall data bytes */
+            			bytes_data = tvb_memdup(tvb, CO_SDO_DATA_OFFSET, 4);
+				proto_tree_add_bytes(canopen_type_tree,
+				    hf_canopen_sdo_data, tvb, CO_SDO_DATA_OFFSET, 4, bytes_data);
+				break;
+		}
+
+        }
+}
+
+
+/* Register the protocol with Wireshark */
+
+/* this format is require because a script is used to build the C function
+   that calls all the protocol registration.
+*/
+
+void
+proto_register_canopen(void)
+{
+        module_t *canopen_module;
+
+        static hf_register_info hf[] = {
+                { &hf_canopen_cob_id,
+                        { "COB-ID",           "canopen.cob_id",
+                        FT_STRINGZ, BASE_NONE, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_type,
+                        { "Type",           "canopen.type",
+                        FT_STRINGZ, BASE_NONE, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_function_code,
+                        { "Function code", "canopen.function_code",
+                        FT_UINT32, BASE_HEX, NULL, 0x780,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_node_id,
+                        { "Node-ID", "canopen.node_id",
+                        FT_UINT32, BASE_HEX, NULL, 0x7F,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_pdo_data,
+                        { "Data", "canopen.pdo.data",
+                        FT_BYTES, BASE_NONE, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_pdo_data_string,
+                        { "Data", "canopen.pdo.data",
+                        FT_STRINGZ, BASE_NONE, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_sdo_cmd,
+                        { "SDO command byte", "canopen.sdo.cmd",
+                        FT_UINT8, BASE_HEX, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_sdo_main_idx,
+                        { "OD main-index", "canopen.sdo.main_idx",
+                        FT_UINT16, BASE_HEX, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_sdo_sub_idx,
+                        { "OD sub-index", "canopen.sdo.sub_idx",
+                        FT_UINT8, BASE_HEX, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_sdo_data,
+                        { "Data", "canopen.sdo.data",
+                        FT_BYTES, BASE_NONE, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_em_err_code,
+                        { "Error code", "canopen.em.err_code",
+                        FT_UINT16, BASE_HEX, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_em_err_reg,
+                        { "Error register", "canopen.em.err_reg",
+                        FT_UINT8, BASE_HEX, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_em_err_field,
+                        { "Manufacture specific error field", "canopen.em.err_field",
+                        FT_BYTES, BASE_NONE, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_nmt_ctrl_cs,
+                        { "Command specifier", "canopen.nmt_ctrl.cd",
+                        FT_UINT8, BASE_HEX, nmt_ctrl_cs, 0xFF,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_nmt_ctrl_node_id,
+                        { "Node-ID", "canopen.nmt_ctrl.node_id",
+                        FT_UINT8, BASE_HEX, NULL, 0x0,
+                        NULL, HFILL }
+                },
+                { &hf_canopen_nmt_guard_state,
+                        { "Node-ID", "canopen.nmt_guard.state",
+                        FT_UINT8, BASE_HEX, nmt_guard_state, 0x7F,
+                        NULL, HFILL }
+                },
+        };
+
+        static gint *ett[] = {
+                &ett_canopen
+        };
+
+	/* Register the protocol name and description */
+        proto_canopen = proto_register_protocol("CANopen",
+						"CANOPEN",
+						"canopen");
+
+	register_dissector("canopen", dissect_canopen, proto_canopen);
+
+	/* Required function calls to register the header fields and subtrees used */
+        proto_register_field_array(proto_canopen, hf, array_length(hf));
+        proto_register_subtree_array(ett, array_length(ett));
+#if 0
+/* Register preferences module (See Section 2.6 for more on preferences) */
+/* (Registration of a prefs callback is not required if there are no     */
+/*  prefs-dependent registration functions (eg: a port pref).            */
+/*  See proto_reg_handoff below.                                         */
+/*  If a prefs callback is not needed, use NULL instead of               */
+/*  proto_reg_handoff_canopen in the following).                     */
+        canopen_module = prefs_register_protocol(proto_canopen,
+            proto_reg_handoff_canopen);
+
+/* Register preferences module under preferences subtree.
+   Use this function instead of prefs_register_protocol if you want to group
+   preferences of several protocols under one preferences subtree.
+   Argument subtree identifies grouping tree node name, several subnodes can be
+   specified usign slash '/' (e.g. "OSI/X.500" - protocol preferences will be
+   accessible under Protocols->OSI->X.500-><CANOPEN> preferences node.
+*/
+
+  canopen_module = prefs_register_protocol_subtree(const char *subtree,
+       proto_canopen, proto_reg_handoff_canopen);
+
+/* Register a sample preference */
+        prefs_register_bool_preference(canopen_module, "show_hex",
+             "Display numbers in Hex",
+             "Enable to display numerical values in hexadecimal.",
+             &gPREF_HEX);
+
+/* Register a sample port preference   */
+        prefs_register_uint_preference(canopen_module, "tcp.port", "canopen TCP Port",
+             " canopen TCP port if other than the default",
+             10, &gPORT_PREF);
+#endif
+}
+
+
+
+#if 1
+/* Simple form of proto_reg_handoff_canopen which can be used if there are
+   no prefs-dependent registration function calls.
+ */
+
+void
+proto_reg_handoff_canopen(void)
+{
+        dissector_handle_t canopen_handle;
+
+/*  Use new_create_dissector_handle() to indicate that dissect_canopen()
+ *  returns the number of bytes it dissected (or 0 if it thinks the packet
+ *  does not belong to CANopen).
+ */
+        canopen_handle = new_create_dissector_handle(dissect_canopen,
+                                                         proto_canopen);
+}
+#endif
+
Index: b/epan/dissectors/packet-socketcan.c
===================================================================
--- a/epan/dissectors/packet-socketcan.c
+++ b/epan/dissectors/packet-socketcan.c
@@ -54,6 +54,7 @@
 static int proto_can = -1;
 
 static dissector_handle_t data_handle;
+static dissector_handle_t canopen_handle;
 
 #define LINUX_CAN_STD 0
 #define LINUX_CAN_EXT 1
@@ -112,8 +113,8 @@
 		proto_tree_add_item(can_tree, hf_can_errflag, tvb, 0, 4, FALSE );
 		proto_tree_add_item(can_tree, hf_can_len, tvb, CAN_LEN_OFFSET, 1, FALSE );
 
-		next_tvb =  tvb_new_subset(tvb, CAN_DATA_OFFSET, tvb_get_guint8(tvb, CAN_LEN_OFFSET), 8 );
-		call_dissector(data_handle, next_tvb, pinfo, tree );
+		//next_tvb =  tvb_new_subset(tvb, CAN_DATA_OFFSET, tvb_get_guint8(tvb, CAN_LEN_OFFSET), 8 );
+		call_dissector(canopen_handle, /*next_*/tvb, pinfo, tree );
 	}
 }
 
@@ -192,7 +193,8 @@
 {
 	dissector_handle_t can_handle;
 
-	data_handle = find_dissector("data");
+	//data_handle = find_dissector("data");
+	canopen_handle = find_dissector("canopen");
 
 	can_handle = create_dissector_handle(dissect_socketcan, proto_can);
 	dissector_add_uint("wtap_encap", WTAP_ENCAP_SOCKETCAN, can_handle);
