2004-09-23 17:34:35 +00:00
|
|
|
/* packet-cip.c
|
|
|
|
* Routines for Common Industrial Protocol (CIP) dissection
|
|
|
|
* CIP Home: www.odva.org
|
|
|
|
*
|
|
|
|
* Copyright 2004
|
|
|
|
* Magnus Hansson <mah@hms.se>
|
|
|
|
* Joakim Wiberg <jow@hms.se>
|
|
|
|
*
|
2007-02-22 03:21:26 +00:00
|
|
|
* Added support for Connection Configuration Object
|
|
|
|
* ryan wamsley * Copyright 2007
|
2009-06-26 02:38:23 +00:00
|
|
|
*
|
|
|
|
* Object dependend services based on IOI
|
|
|
|
* Jan Bartels, Siempelkamp Maschinen- und Anlagenbau GmbH & Co. KG
|
|
|
|
* Copyright 2007
|
2007-02-22 03:21:26 +00:00
|
|
|
*
|
2004-09-23 17:34:35 +00:00
|
|
|
* $Id$
|
|
|
|
*
|
2006-05-21 04:49:01 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2004-09-23 17:34:35 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/*
|
|
|
|
&ett_cip, dissect_cip
|
|
|
|
&ett_path, dissect_epath
|
|
|
|
&ett_ekey_path, dissect_epath
|
|
|
|
&ett_mcsc, dissect_epath,
|
|
|
|
&ett_cia_path, dissect_epath
|
|
|
|
&ett_data_seg, dissect_epath
|
|
|
|
&ett_port_path, dissect_epath
|
|
|
|
&ett_rrsc, dissect_cip_generic_data, dissect_cip_mr_data, dissect_cip_cm_data, dissect_cip_cco_data, dissect_cip_pccc_data
|
|
|
|
&ett_status_item dissect_cip_generic_data, dissect_cip_mr_data, dissect_cip_cm_data, dissect_cip_cco_data, dissect_cip_pccc_data
|
|
|
|
|
|
|
|
&ett_cmd_data, dissect_cip_generic_data, dissect_cip_mr_data, dissect_cip_cm_data, dissect_cip_cco_data, dissect_cip_pccc_data
|
|
|
|
&ett_ncp, dissect_cip_cm_data
|
|
|
|
&ett_mes_req, dissect_cip_cm_data
|
|
|
|
&ett_mult_ser, dissect_cip_mr_data
|
|
|
|
*/
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include <epan/packet.h>
|
2009-06-26 02:38:23 +00:00
|
|
|
#include "packet-enip.h"
|
2004-09-23 17:34:35 +00:00
|
|
|
#include "packet-cip.h"
|
|
|
|
|
|
|
|
#define ENIP_CIP_INTERFACE 0
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
typedef struct cip_req_info {
|
|
|
|
dissector_handle_t dissector;
|
|
|
|
guint8 bService;
|
|
|
|
guint IOILen;
|
|
|
|
void *pIOI;
|
|
|
|
void *pData;
|
|
|
|
} cip_req_info_t;
|
|
|
|
|
|
|
|
dissector_handle_t cip_handle;
|
|
|
|
dissector_handle_t cip_class_generic_handle,cip_class_cm_handle,cip_class_mr_handle;
|
|
|
|
dissector_handle_t cip_class_cco_handle;
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
/* Initialize the protocol and registered fields */
|
2009-06-26 02:38:23 +00:00
|
|
|
static int proto_cip = -1;
|
|
|
|
static int proto_cip_class_generic = -1;
|
|
|
|
static int proto_cip_class_cm = -1;
|
|
|
|
static int proto_cip_class_mr = -1;
|
|
|
|
static int proto_cip_class_cco = -1;
|
|
|
|
static int proto_enip = -1;
|
|
|
|
|
|
|
|
static int hf_cip_sc = -1;
|
|
|
|
static int hf_cip_rr = -1;
|
|
|
|
static int hf_cip_epath = -1;
|
|
|
|
static int hf_cip_genstat = -1;
|
|
|
|
|
|
|
|
static int hf_cip_fwo_comp = -1;
|
|
|
|
static int hf_cip_fwo_mrev = -1;
|
|
|
|
|
|
|
|
static int hf_cip_cm_sc = -1;
|
|
|
|
static int hf_cip_cm_rr = -1;
|
|
|
|
static int hf_cip_cm_fwo_comp = -1;
|
|
|
|
static int hf_cip_cm_fwo_mrev = -1;
|
|
|
|
static int hf_cip_cm_fwo_con_size = -1;
|
|
|
|
static int hf_cip_cm_fwo_fixed_var = -1;
|
|
|
|
static int hf_cip_cm_fwo_prio = -1;
|
|
|
|
static int hf_cip_cm_fwo_typ = -1;
|
|
|
|
static int hf_cip_cm_fwo_own = -1;
|
|
|
|
static int hf_cip_cm_fwo_dir = -1;
|
|
|
|
static int hf_cip_cm_fwo_trigg = -1;
|
|
|
|
static int hf_cip_cm_fwo_class = -1;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
static int hf_cip_vendor = -1;
|
|
|
|
static int hf_cip_devtype = -1;
|
|
|
|
static int hf_cip_port = -1;
|
|
|
|
static int hf_cip_link_address_byte = -1;
|
|
|
|
static int hf_cip_link_address_string = -1;
|
|
|
|
static int hf_cip_class8 = -1;
|
|
|
|
static int hf_cip_class16 = -1;
|
|
|
|
static int hf_cip_class32 = -1;
|
|
|
|
static int hf_cip_instance8 = -1;
|
|
|
|
static int hf_cip_instance16 = -1;
|
|
|
|
static int hf_cip_instance32 = -1;
|
2009-06-26 02:38:23 +00:00
|
|
|
static int hf_cip_member8 = -1;
|
|
|
|
static int hf_cip_member16 = -1;
|
|
|
|
static int hf_cip_member32 = -1;
|
2004-09-23 17:34:35 +00:00
|
|
|
static int hf_cip_attribute8 = -1;
|
|
|
|
static int hf_cip_attribute16 = -1;
|
|
|
|
static int hf_cip_attribute32 = -1;
|
|
|
|
static int hf_cip_conpoint8 = -1;
|
|
|
|
static int hf_cip_conpoint16 = -1;
|
|
|
|
static int hf_cip_conpoint32 = -1;
|
|
|
|
static int hf_cip_symbol = -1;
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
static int hf_cip_mr_sc = -1;
|
|
|
|
static int hf_cip_mr_rr = -1;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
static int hf_cip_cco_sc = -1;
|
|
|
|
static int hf_cip_cco_rr = -1;
|
2009-06-19 06:15:52 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Initialize the subtree pointers */
|
|
|
|
static gint ett_cip = -1;
|
|
|
|
static gint ett_cip_class_generic = -1;
|
|
|
|
static gint ett_cip_class_mr = -1;
|
|
|
|
static gint ett_cip_class_cm = -1;
|
|
|
|
static gint ett_cip_class_cco = -1;
|
|
|
|
|
|
|
|
static gint ett_path = -1;
|
|
|
|
static gint ett_ekey_path = -1;
|
|
|
|
static gint ett_mcsc = -1;
|
|
|
|
static gint ett_cia_path = -1;
|
|
|
|
static gint ett_data_seg = -1;
|
|
|
|
static gint ett_port_path = -1;
|
|
|
|
|
|
|
|
static gint ett_rrsc = -1;
|
|
|
|
static gint ett_status_item = -1;
|
|
|
|
static gint ett_cmd_data = -1;
|
|
|
|
|
|
|
|
static gint ett_cm_rrsc = -1;
|
|
|
|
static gint ett_cm_ncp = -1;
|
|
|
|
static gint ett_cm_mes_req = -1;
|
|
|
|
static gint ett_cm_cmd_data = -1;
|
|
|
|
|
|
|
|
static gint ett_mr_rrsc = -1;
|
|
|
|
static gint ett_mr_mult_ser = -1;
|
|
|
|
static gint ett_mr_cmd_data = -1;
|
|
|
|
|
|
|
|
static gint ett_cco_rrsc = -1;
|
|
|
|
static gint ett_cco_cmd_data = -1;
|
|
|
|
|
|
|
|
static dissector_table_t subdissector_class_table;
|
|
|
|
static dissector_table_t subdissector_symbol_table;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Translate function to string - CIP Service codes */
|
|
|
|
static const value_string cip_sc_vals[] = {
|
2009-07-06 13:59:09 +00:00
|
|
|
GENERIC_SC_LIST
|
2009-06-26 02:38:23 +00:00
|
|
|
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - CIP Service codes for CM */
|
|
|
|
static const value_string cip_sc_vals_cm[] = {
|
2009-07-06 13:59:09 +00:00
|
|
|
GENERIC_SC_LIST
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Some class specific services */
|
|
|
|
{ SC_CM_FWD_CLOSE, "Forward Close" },
|
|
|
|
{ SC_CM_FWD_OPEN, "Forward Open" },
|
|
|
|
{ SC_CM_UNCON_SEND, "Unconnected Send" },
|
|
|
|
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
2009-06-19 06:15:52 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Translate function to string - CIP Service codes for CCO */
|
|
|
|
static const value_string cip_sc_vals_cco[] = {
|
2009-07-06 13:59:09 +00:00
|
|
|
GENERIC_SC_LIST
|
|
|
|
|
|
|
|
/* Some class specific services */
|
2009-06-26 02:38:23 +00:00
|
|
|
{ SC_CCO_KICK_TIMER, "Kick Timer" },
|
|
|
|
{ SC_CCO_OPEN_CONN, "Open Connection" },
|
|
|
|
{ SC_CCO_CLOSE_CONN, "Close Connection" },
|
|
|
|
{ SC_CCO_STOP_CONN, "Stop Connection" },
|
|
|
|
{ SC_CCO_CHANGE_START, "Change Start" },
|
|
|
|
{ SC_CCO_GET_STATUS, "Get Status" },
|
|
|
|
{ SC_CCO_CHANGE_COMPLETE, "Change Complete" },
|
|
|
|
{ SC_CCO_AUDIT_CHANGE, "Audit Changes" },
|
|
|
|
|
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - CIP Request/Response */
|
|
|
|
static const value_string cip_sc_rr[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Request" },
|
|
|
|
{ 1, "Response" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Compatibility */
|
|
|
|
static const value_string cip_com_bit_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Bit Cleared" },
|
|
|
|
{ 1, "Bit Set" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Connection priority */
|
|
|
|
static const value_string cip_con_prio_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Low Priority" },
|
|
|
|
{ 1, "High Priority" },
|
|
|
|
{ 2, "Scheduled" },
|
|
|
|
{ 3, "Urgent" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Connection size fixed or variable */
|
|
|
|
static const value_string cip_con_fw_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Fixed" },
|
|
|
|
{ 1, "Variable" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Connection owner */
|
|
|
|
static const value_string cip_con_owner_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Exclusive" },
|
|
|
|
{ 1, "Redundant" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Connection direction */
|
|
|
|
static const value_string cip_con_dir_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Client" },
|
|
|
|
{ 1, "Server" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Production trigger */
|
|
|
|
static const value_string cip_con_trigg_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Cyclic" },
|
|
|
|
{ 1, "Change-Of-State" },
|
|
|
|
{ 2, "Application Object" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Transport class */
|
|
|
|
static const value_string cip_con_class_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "0" },
|
|
|
|
{ 1, "1" },
|
|
|
|
{ 2, "2" },
|
|
|
|
{ 3, "3" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Connection type */
|
|
|
|
static const value_string cip_con_type_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "Null" },
|
|
|
|
{ 1, "Multicast" },
|
|
|
|
{ 2, "Point to Point" },
|
|
|
|
{ 3, "Reserved" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - Timeout Multiplier */
|
|
|
|
static const value_string cip_con_time_mult_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, "*4" },
|
|
|
|
{ 1, "*8" },
|
|
|
|
{ 2, "*16" },
|
|
|
|
{ 3, "*32" },
|
|
|
|
{ 4, "*64" },
|
|
|
|
{ 5, "*128" },
|
|
|
|
{ 6, "*256" },
|
|
|
|
{ 7, "*512" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate function to string - CIP General Status codes */
|
|
|
|
static const value_string cip_gs_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ CI_GRC_SUCCESS, "Success" },
|
2004-09-23 17:34:35 +00:00
|
|
|
{ CI_GRC_FAILURE, "Connection failure" },
|
|
|
|
{ CI_GRC_NO_RESOURCE, "Resource unavailable" },
|
|
|
|
{ CI_GRC_BAD_DATA, "Invalid parameter value" },
|
|
|
|
{ CI_GRC_BAD_PATH, "Path segment error" },
|
|
|
|
{ CI_GRC_BAD_CLASS_INSTANCE, "Path destination unknown" },
|
|
|
|
{ CI_GRC_PARTIAL_DATA, "Partial transfer" },
|
|
|
|
{ CI_GRC_CONN_LOST, "Connection lost" },
|
|
|
|
{ CI_GRC_BAD_SERVICE, "Service not supported" },
|
|
|
|
{ CI_GRC_BAD_ATTR_DATA, "Invalid attribute value" },
|
|
|
|
{ CI_GRC_ATTR_LIST_ERROR, "Attribute list error" },
|
|
|
|
{ CI_GRC_ALREADY_IN_MODE, "Already in requested mode/state" },
|
|
|
|
{ CI_GRC_BAD_OBJ_MODE, "Object state conflict" },
|
|
|
|
{ CI_GRC_OBJ_ALREADY_EXISTS, "Object already exists" },
|
|
|
|
{ CI_GRC_ATTR_NOT_SETTABLE, "Attribute not settable" },
|
|
|
|
{ CI_GRC_PERMISSION_DENIED, "Privilege violation" },
|
|
|
|
{ CI_GRC_DEV_IN_WRONG_STATE, "Device state conflict" },
|
|
|
|
{ CI_GRC_REPLY_DATA_TOO_LARGE,"Reply data too large" },
|
|
|
|
{ CI_GRC_FRAGMENT_PRIMITIVE, "Fragmentation of a primitive value" },
|
|
|
|
{ CI_GRC_CONFIG_TOO_SMALL, "Not enough data" },
|
|
|
|
{ CI_GRC_UNDEFINED_ATTR, "Attribute not supported" },
|
|
|
|
{ CI_GRC_CONFIG_TOO_BIG, "Too much data" },
|
|
|
|
{ CI_GRC_OBJ_DOES_NOT_EXIST, "Object does not exist" },
|
|
|
|
{ CI_GRC_NO_FRAGMENTATION, "Service fragmentation sequence not in progress" },
|
|
|
|
{ CI_GRC_DATA_NOT_SAVED, "No stored attribute data" },
|
|
|
|
{ CI_GRC_DATA_WRITE_FAILURE, "Store operation failure" },
|
|
|
|
{ CI_GRC_REQUEST_TOO_LARGE, "Routing failure, request packet too large" },
|
|
|
|
{ CI_GRC_RESPONSE_TOO_LARGE, "Routing failure, response packet too large" },
|
|
|
|
{ CI_GRC_MISSING_LIST_DATA, "Missing attribute list entry data" },
|
|
|
|
{ CI_GRC_INVALID_LIST_STATUS, "Invalid attribute value list" },
|
|
|
|
{ CI_GRC_SERVICE_ERROR, "Embedded service error" },
|
|
|
|
{ CI_GRC_CONN_RELATED_FAILURE,"Vendor specific error" },
|
|
|
|
{ CI_GRC_INVALID_PARAMETER, "Invalid parameter" },
|
|
|
|
{ CI_GRC_WRITE_ONCE_FAILURE, "Write-once value or medium already written" },
|
2009-07-06 13:59:09 +00:00
|
|
|
{ CI_GRC_INVALID_REPLY, "Invalid reply received" },
|
|
|
|
{ CI_GRC_BUFFER_OVERFLOW, "Buffer overflow" },
|
|
|
|
{ CI_GRC_MESSAGE_FORMAT, "Invalid message format" },
|
|
|
|
{ CI_GRC_BAD_KEY_IN_PATH, "Key failure in path" },
|
|
|
|
{ CI_GRC_BAD_PATH_SIZE, "Path size invalid" },
|
2004-09-23 17:34:35 +00:00
|
|
|
{ CI_GRC_UNEXPECTED_ATTR, "Unexpected attribute in list" },
|
|
|
|
{ CI_GRC_INVALID_MEMBER, "Invalid Member ID" },
|
|
|
|
{ CI_GRC_MEMBER_NOT_SETTABLE, "Member not settable" },
|
2009-07-06 13:59:09 +00:00
|
|
|
{ CI_GRC_G2_SERVER_FAILURE, "Group 2 only server general failure" },
|
|
|
|
{ CI_GRC_UNKNOWN_MB_ERROR, "Unknown Modbus error" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate Vendor ID:s */
|
|
|
|
const value_string cip_vendor_vals[] = {
|
|
|
|
VENDOR_ID_LIST
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Translate Device Profile:s */
|
|
|
|
const value_string cip_devtype_vals[] = {
|
|
|
|
{ DP_GEN_DEV, "Generic Device" },
|
|
|
|
{ DP_AC_DRIVE, "AC Drive" },
|
|
|
|
{ DP_MOTOR_OVERLOAD, "Motor Overload" },
|
|
|
|
{ DP_LIMIT_SWITCH, "Limit Switch" },
|
|
|
|
{ DP_IND_PROX_SWITCH, "Inductive Proximity Switch" },
|
|
|
|
{ DP_PHOTO_SENSOR, "Photoelectric Sensor" },
|
2008-12-17 17:23:37 +00:00
|
|
|
{ DP_GENP_DISC_IO, "General Purpose Discrete I/O"},
|
2004-09-23 17:34:35 +00:00
|
|
|
{ DP_RESOLVER, "Resolver" },
|
|
|
|
{ DP_COM_ADAPTER, "Communications Adapter" },
|
|
|
|
{ DP_POS_CNT, "Position Controller", },
|
|
|
|
{ DP_DC_DRIVE, "DC Drive" },
|
|
|
|
{ DP_CONTACTOR, "Contactor", },
|
|
|
|
{ DP_MOTOR_STARTER, "Motor Starter", },
|
|
|
|
{ DP_SOFT_START, "Soft Start", },
|
|
|
|
{ DP_HMI, "Human-Machine Interface" },
|
|
|
|
{ DP_MASS_FLOW_CNT, "Mass Flow Controller" },
|
|
|
|
{ DP_PNEUM_VALVE, "Pneumatic Valve" },
|
2008-12-18 19:08:49 +00:00
|
|
|
{ DP_VACUUM_PRES_GAUGE, "Vacuum Pressure Gauge" },
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
#define CI_CLS_MR 0x02 /* Message Router */
|
|
|
|
#define CI_CLS_CM 0x06 /* Connection Manager */
|
|
|
|
#define CI_CLS_CCO 0xF3 /* Connection Configuration Object */
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
/* Translate class names */
|
|
|
|
static const value_string cip_class_names_vals[] = {
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0x01, "Identity Object" },
|
|
|
|
{ 0x02, "Message Router" },
|
|
|
|
{ 0x03, "DeviceNet Object" },
|
|
|
|
{ 0x04, "Assembly Object" },
|
|
|
|
{ 0x05, "Connection Object" },
|
|
|
|
{ 0x06, "Connection Manager" },
|
|
|
|
{ 0x07, "Register Object" },
|
|
|
|
{ 0x08, "Discrete Input Point Object" },
|
|
|
|
{ 0x09, "Discrete Output Point Object" },
|
|
|
|
{ 0x0A, "Analog Input Point Object" },
|
|
|
|
{ 0x0B, "Analog Output Point Object" },
|
|
|
|
{ 0x0E, "Presence Sensing Object" },
|
|
|
|
{ 0x0F, "Parameter Object" },
|
|
|
|
{ 0x10, "Parameter Group Object" },
|
|
|
|
{ 0x12, "Group Object" },
|
|
|
|
{ 0x1D, "Discrete Input Group Object" },
|
|
|
|
{ 0x1E, "Discrete Output Group Object" },
|
|
|
|
{ 0x1F, "Discrete Group Object" },
|
|
|
|
{ 0x20, "Analog Input Group Object" },
|
|
|
|
{ 0x21, "Analog Output Group Object" },
|
|
|
|
{ 0x22, "Analog Group Object" },
|
|
|
|
{ 0x23, "Position Sensor Object" },
|
|
|
|
{ 0x24, "Position Controller Supervisor Object" },
|
|
|
|
{ 0x25, "Position Controller Object" },
|
|
|
|
{ 0x26, "Block Sequencer Object" },
|
|
|
|
{ 0x27, "Command Block Object" },
|
|
|
|
{ 0x28, "Motor Data Object" },
|
|
|
|
{ 0x29, "Control Supervisor Object" },
|
|
|
|
{ 0x2A, "AC/DC Drive Object" },
|
|
|
|
{ 0x2B, "Acknowledge Handler Object" },
|
|
|
|
{ 0x2C, "Overload Object" },
|
|
|
|
{ 0x2D, "Softstart Object" },
|
|
|
|
{ 0x2E, "Selection Object" },
|
|
|
|
{ 0x30, "S-Device Supervisor Object" },
|
|
|
|
{ 0x31, "S-Analog Sensor Object" },
|
|
|
|
{ 0x32, "S-Analog Actuator Object" },
|
|
|
|
{ 0x33, "S-Single Stage Controller Object" },
|
|
|
|
{ 0x34, "S-Gas Calibration Object" },
|
|
|
|
{ 0x35, "Trip Point Object" },
|
|
|
|
{ 0x37, "File Object" },
|
|
|
|
{ 0x38, "S-Partial Pressure Object" },
|
2009-07-06 13:59:09 +00:00
|
|
|
{ 0x39, "Safety Supervisor Object" },
|
|
|
|
{ 0x3A, "Safety Validator Object" },
|
|
|
|
{ 0x3B, "Safety Discrete Output Point Object" },
|
|
|
|
{ 0x3C, "Safety Discrete Output Group Object" },
|
|
|
|
{ 0x3D, "Safety Discrete Input Point Object" },
|
|
|
|
{ 0x3E, "Safety Discrete Input Group Object" },
|
|
|
|
{ 0x3F, "Safety Dual Channel Output Object" },
|
|
|
|
{ 0x40, "S-Sensor Calibration Object" },
|
|
|
|
{ 0x41, "Event Log Object" },
|
|
|
|
{ 0x42, "Motion Axis Object" },
|
|
|
|
{ 0x43, "Time Sync Object" },
|
|
|
|
{ 0x44, "Modbus Object" },
|
|
|
|
{ 0x45, "Originator Connection List Object" },
|
|
|
|
{ 0x46, "Modbus Serial Link Object" },
|
|
|
|
{ 0x47, "Device Level Ring (DLR) Object" },
|
|
|
|
{ 0x48, "QoS Object" },
|
2009-06-26 02:38:23 +00:00
|
|
|
{ 0xF0, "ControlNet Object" },
|
|
|
|
{ 0xF1, "ControlNet Keeper Object" },
|
|
|
|
{ 0xF2, "ControlNet Scheduling Object" },
|
|
|
|
{ 0xF3, "Connection Configuration Object" },
|
|
|
|
{ 0xF4, "Port Object" },
|
|
|
|
{ 0xF5, "TCP/IP Interface Object" },
|
|
|
|
{ 0xF6, "EtherNet Link Object" },
|
2009-07-06 13:59:09 +00:00
|
|
|
{ 0xF7, "CompoNet Object" },
|
|
|
|
{ 0xF8, "CompoNet Repeater Object" },
|
2009-06-26 02:38:23 +00:00
|
|
|
|
|
|
|
{ 0, NULL }
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
static void
|
|
|
|
dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info *pinfo, cip_req_info_t *preq_info );
|
|
|
|
|
|
|
|
static proto_item*
|
|
|
|
add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
|
|
|
|
{
|
|
|
|
const guint8 *tmp;
|
|
|
|
char *tmp2, *tmp2start;
|
|
|
|
proto_item *pi;
|
|
|
|
int i,tmp_length,tmp2_length;
|
|
|
|
guint32 octet;
|
|
|
|
/* At least one version of Apple's C compiler/linker is buggy, causing
|
|
|
|
a complaint from the linker about the "literal C string section"
|
|
|
|
not ending with '\0' if we initialize a 16-element "char" array with
|
|
|
|
a 16-character string, the fact that initializing such an array with
|
|
|
|
such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
|
|
|
|
'\0' byte in the string nonwithstanding. */
|
|
|
|
static const char my_hex_digits[16] =
|
|
|
|
{ '0', '1', '2', '3', '4', '5', '6', '7',
|
|
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
|
|
|
|
|
|
|
|
|
|
if( ( length * 2 ) > 32 )
|
|
|
|
{
|
|
|
|
tmp_length = 16;
|
|
|
|
tmp2_length = 36;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp_length = length;
|
|
|
|
tmp2_length = ( length * 2 ) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = tvb_get_ptr( tvb, start, tmp_length );
|
|
|
|
tmp2 = (char*)ep_alloc( tmp2_length );
|
|
|
|
|
|
|
|
tmp2start = tmp2;
|
|
|
|
|
|
|
|
for( i = 0; i < tmp_length; i++ )
|
|
|
|
{
|
|
|
|
octet = tmp[i];
|
|
|
|
octet >>= 4;
|
|
|
|
*tmp2++ = my_hex_digits[octet&0xF];
|
|
|
|
octet = tmp[i];
|
|
|
|
*tmp2++ = my_hex_digits[octet&0xF];
|
|
|
|
}
|
|
|
|
|
|
|
|
if( tmp_length != length )
|
|
|
|
{
|
|
|
|
*tmp2++ = '.';
|
|
|
|
*tmp2++ = '.';
|
|
|
|
*tmp2++ = '.';
|
|
|
|
}
|
|
|
|
|
|
|
|
*tmp2 = 0;
|
|
|
|
|
|
|
|
pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
|
|
|
|
|
|
|
|
return( pi );
|
|
|
|
|
|
|
|
} /* end of add_byte_array_text_to_proto_tree() */
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Dissect EPATH */
|
|
|
|
static void
|
2009-06-26 02:38:23 +00:00
|
|
|
dissect_epath( tvbuff_t *tvb, proto_item *epath_item, int offset, int path_length, gboolean generate )
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
|
|
|
int pathpos, temp_data, temp_data2, seg_size, i, temp_word;
|
|
|
|
unsigned char segment_type, opt_link_size;
|
|
|
|
proto_tree *path_tree, *port_tree, *net_tree;
|
|
|
|
proto_item *qi, *cia_item, *ds_item;
|
|
|
|
proto_tree *e_key_tree, *cia_tree, *ds_tree;
|
|
|
|
proto_item *mcpi, *port_item, *net_item;
|
|
|
|
proto_tree *mc_tree;
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_item *it;
|
2008-05-15 01:44:53 +00:00
|
|
|
proto_item *hidden_item;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the epath */
|
|
|
|
path_tree = proto_item_add_subtree( epath_item, ett_path );
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( !generate )
|
|
|
|
{
|
|
|
|
hidden_item = proto_tree_add_item(path_tree, hf_cip_epath,
|
|
|
|
tvb, offset, path_length, TRUE );
|
|
|
|
PROTO_ITEM_SET_HIDDEN(hidden_item);
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
pathpos = 0;
|
|
|
|
|
|
|
|
while( pathpos < path_length )
|
|
|
|
{
|
|
|
|
/* Get segement type */
|
|
|
|
segment_type = tvb_get_guint8( tvb, offset + pathpos );
|
|
|
|
|
|
|
|
/* Determine the segment type */
|
|
|
|
|
|
|
|
switch( segment_type & CI_SEGMENT_TYPE_MASK )
|
|
|
|
{
|
|
|
|
case CI_PORT_SEGMENT:
|
|
|
|
|
|
|
|
port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
port_item = proto_tree_add_text( path_tree, NULL, 0, 0, "Port Segment" );
|
|
|
|
PROTO_ITEM_SET_GENERATED(port_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
|
2004-09-23 17:34:35 +00:00
|
|
|
port_tree = proto_item_add_subtree( port_item, ett_port_path );
|
|
|
|
|
|
|
|
/* Add port number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(port_tree, hf_cip_port, NULL, 0, 0, ( segment_type & 0x0F ) );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( port_tree, hf_cip_port, tvb, offset + pathpos, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "Port: %d", ( segment_type & 0x0F ) );
|
|
|
|
proto_item_append_text( port_item, ": Port: %d", ( segment_type & 0x0F ) );
|
|
|
|
|
|
|
|
if( segment_type & 0x10 )
|
|
|
|
{
|
|
|
|
/* Add Extended Link Address flag */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_text( port_tree, NULL, 0, 0, "Extended Link Address: TRUE" );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
it = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: TRUE" );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Add size of extended link address */
|
|
|
|
opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_text( port_tree, NULL, 0, 0, "Link Address Size: %d", opt_link_size );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
it = proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Add extended link address */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_string(port_tree, hf_cip_link_address_string, NULL, 0, 0, tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( port_tree, hf_cip_link_address_string, tvb, offset+pathpos+2, opt_link_size, FALSE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
|
|
|
|
proto_item_append_text( port_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
|
|
|
|
|
|
|
|
/* Pad byte */
|
|
|
|
if( opt_link_size % 2 )
|
|
|
|
{
|
|
|
|
proto_item_set_len( port_item, 3 + opt_link_size );
|
|
|
|
pathpos = pathpos + 3 + opt_link_size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
proto_item_set_len( port_item, 2 + opt_link_size );
|
|
|
|
pathpos = pathpos + 2 + opt_link_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add Extended Link Address flag */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_text( port_tree, NULL, 0, 0, "Extended Link Address: FALSE" );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
it = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: FALSE" );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Add Link Address */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(port_tree, hf_cip_link_address_byte, NULL, 0, 0, tvb_get_guint8( tvb, offset + pathpos + 1 ) );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( port_tree, hf_cip_link_address_byte, tvb, offset+pathpos+1, 1, FALSE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
|
|
|
|
proto_item_append_text( port_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
|
|
|
|
|
|
|
|
proto_item_set_len( port_item, 2 );
|
|
|
|
pathpos += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CI_LOGICAL_SEGMENT:
|
|
|
|
|
|
|
|
/* Logical segment, determin the logical type */
|
|
|
|
|
|
|
|
switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
|
|
|
|
{
|
|
|
|
case CI_LOGICAL_SEG_CLASS_ID:
|
|
|
|
|
|
|
|
/* Logical Class ID, do a format check */
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
|
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Class Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Class Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the class */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 8-bit class number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(cia_tree, hf_cip_class8, NULL, 0, 0, temp_data );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_class8, tvb, offset + pathpos + 1, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%02X" ) );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Class Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Class Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the class */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 16-bit class number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(cia_tree, hf_cip_class16, NULL, 0, 0, temp_data );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_class16, tvb, offset + pathpos + 2, 2, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%04X" ) );
|
|
|
|
|
|
|
|
/* 4 bytes of path used */
|
|
|
|
pathpos += 4;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the class */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 32-bit class number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(cia_tree, hf_cip_class32, NULL, 0, 0, temp_data );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_class32, tvb, offset + pathpos + 2, 4, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%08X" ) );
|
|
|
|
|
|
|
|
/* 6 bytes of path used */
|
|
|
|
pathpos += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unsupported logical segment format */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CI_LOGICAL_SEG_INST_ID:
|
|
|
|
|
|
|
|
/* Logical Instance ID, do a format check */
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
|
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the instance */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 8-bit instance number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(cia_tree, hf_cip_instance8, NULL, 0, 0, temp_data );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_instance8, tvb, offset + pathpos + 1, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "Instance: 0x%02X", temp_data );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the instance */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 16-bit instance number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(cia_tree, hf_cip_instance16, NULL, 0, 0, temp_data );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_instance16, tvb, offset + pathpos + 2, 2, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "Instance: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* 4 bytes of path used */
|
|
|
|
pathpos += 4;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the instance */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 32-bit instance number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_uint(cia_tree, hf_cip_instance32, NULL, 0, 0, temp_data );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_instance32, tvb, offset + pathpos + 2, 4, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "Instance: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
|
|
|
|
/* 6 bytes of path used */
|
|
|
|
pathpos += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unsupported logical segment format */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
case CI_LOGICAL_SEG_MBR_ID:
|
|
|
|
|
|
|
|
/* Logical Member ID, do a format check */
|
|
|
|
|
|
|
|
if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
|
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Member Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Member Segment (0x%02X)", segment_type );
|
|
|
|
|
|
|
|
/* Create a sub tree for the attribute */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 8-bit attribute number */
|
|
|
|
if ( generate )
|
|
|
|
{
|
2009-09-22 05:49:15 +00:00
|
|
|
it = proto_tree_add_uint( cia_tree, hf_cip_member8, NULL, 0, 0, temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_member8, tvb, offset + pathpos + 1, 1, TRUE );
|
|
|
|
proto_item_append_text( epath_item, "Member: 0x%02X", temp_data );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
|
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Member Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Member Segment (0x%02X)", segment_type );
|
|
|
|
|
|
|
|
/* Create a sub tree for the attribute */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 16-bit attribute number */
|
|
|
|
if ( generate )
|
|
|
|
{
|
2009-09-22 05:49:15 +00:00
|
|
|
it = proto_tree_add_uint( cia_tree, hf_cip_member16, NULL, 0, 0, temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_member16, tvb, offset + pathpos + 2, 2, TRUE );
|
|
|
|
proto_item_append_text( epath_item, "Member: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* 4 bytes of path used */
|
|
|
|
pathpos += 4;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
|
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Member Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Member Segment (0x%02X)", segment_type );
|
|
|
|
|
|
|
|
/* Create a sub tree for the attribute */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 32-bit attribute number */
|
|
|
|
if ( generate )
|
|
|
|
{
|
2009-09-22 05:49:15 +00:00
|
|
|
it = proto_tree_add_uint( cia_tree, hf_cip_member32, NULL, 0, 0, temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_member32, tvb, offset + pathpos + 2, 4, TRUE );
|
|
|
|
proto_item_append_text( epath_item, "Member: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
/* 6 bytes of path used */
|
|
|
|
pathpos += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unsupported logical segment format */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
case CI_LOGICAL_SEG_ATTR_ID:
|
|
|
|
|
|
|
|
/* Logical Attribute ID, do a format check */
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
|
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the attribute */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 8-bit attribute number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
2009-09-22 05:49:15 +00:00
|
|
|
it = proto_tree_add_uint( cia_tree, hf_cip_attribute8, NULL, 0, 0, temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_attribute8, tvb, offset + pathpos + 1, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "Attribute: 0x%02X", temp_data );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the attribute */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 16-bit attribute number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
2009-09-22 05:49:15 +00:00
|
|
|
it = proto_tree_add_uint( cia_tree, hf_cip_attribute16, NULL, 0, 0, temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_attribute16, tvb, offset + pathpos + 2, 2, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "Attribute: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* 4 bytes of path used */
|
|
|
|
pathpos += 4;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(cia_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree for the attribute */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 32-bit attribute number */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
2009-09-22 05:49:15 +00:00
|
|
|
it = proto_tree_add_uint( cia_tree, hf_cip_attribute32, NULL, 0, 0, temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_attribute32, tvb, offset + pathpos + 2, 4, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( epath_item, "Attribute: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
/* 6 bytes of path used */
|
|
|
|
pathpos += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unsupported logical segment format */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CI_LOGICAL_SEG_CON_POINT:
|
|
|
|
|
|
|
|
/* Logical Connection point , do a format check */
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
|
2004-09-23 17:34:35 +00:00
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Connection Point Segment (0x%02X)", segment_type );
|
|
|
|
|
|
|
|
/* Create a sub tree for the connection point */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 8-bit connection point number */
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_conpoint8, tvb, offset + pathpos + 1, 1, TRUE );
|
|
|
|
proto_item_append_text( epath_item, "Connection Point: 0x%02X", temp_data );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Connection Point Segment (0x%02X)", segment_type );
|
|
|
|
|
|
|
|
/* Create a sub tree for the connection point */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 16-bit connection point number */
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_conpoint16, tvb, offset + pathpos + 2, 2, TRUE );
|
|
|
|
proto_item_append_text( epath_item, "Connection Point: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* 4 bytes of path used */
|
|
|
|
pathpos += 4;
|
|
|
|
}
|
|
|
|
else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
|
|
|
|
{
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
|
|
|
|
cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Connection Point Segment (0x%02X)", segment_type );
|
|
|
|
|
|
|
|
/* Create a sub tree for the connection point */
|
|
|
|
cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
|
|
|
|
|
|
|
|
/* Display the 32-bit connection point number */
|
|
|
|
proto_tree_add_item( cia_tree, hf_cip_conpoint32, tvb, offset + pathpos + 2, 4, TRUE );
|
|
|
|
proto_item_append_text( epath_item, "Connection Point: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
/* 6 bytes of path used */
|
|
|
|
pathpos += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unsupported logical segment format */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CI_LOGICAL_SEG_SPECIAL:
|
|
|
|
|
|
|
|
/* Logical Special ID, the only logical format sepcifyed is electronic key */
|
|
|
|
|
|
|
|
if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
|
|
|
|
{
|
|
|
|
/* Get the Key Format */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
|
|
|
|
|
|
|
|
if( temp_data == CI_E_KEY_FORMAT_VAL )
|
|
|
|
{
|
|
|
|
qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
|
|
|
|
|
|
|
|
/* Create a sub tree for the IOI */
|
|
|
|
e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
|
|
|
|
|
|
|
|
/* Print the key type */
|
|
|
|
proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
|
|
|
|
|
|
|
|
/* Get the Vendor ID */
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_tree_add_item( e_key_tree, hf_cip_vendor, tvb, offset + pathpos + 2, 2, TRUE);
|
|
|
|
proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* Get Device Type */
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
|
|
|
|
proto_tree_add_item( e_key_tree, hf_cip_devtype, tvb, offset + pathpos + 4, 2, TRUE);
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* Product Code */
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* Major revision/Compatibility */
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add Major revision/Compatibility tree */
|
|
|
|
mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
|
|
|
|
mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add Compatibility bit info */
|
2004-09-23 17:34:35 +00:00
|
|
|
proto_tree_add_item(mc_tree, hf_cip_fwo_comp,
|
2009-06-26 02:38:23 +00:00
|
|
|
tvb, offset + pathpos + 8, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
proto_item_append_text( mcpi, "%s, Major Revision: %d",
|
|
|
|
val_to_str( ( temp_data & 0x80 )>>7, cip_com_bit_vals , "" ),
|
|
|
|
temp_data & 0x7F );
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Major revision */
|
|
|
|
proto_tree_add_item(mc_tree, hf_cip_fwo_mrev,
|
|
|
|
tvb, offset + pathpos + 8, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Minor revision */
|
|
|
|
temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
|
|
|
|
proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
|
|
|
|
|
|
|
|
proto_item_append_text( qi, ", %d.%d", ( temp_data & 0x7F ), temp_data2 );
|
|
|
|
|
|
|
|
proto_item_append_text(epath_item, "[Key]" );
|
|
|
|
|
|
|
|
/* Increment the path pointer */
|
|
|
|
pathpos += 10;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unsupported electronic key format */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unsupported special segment format */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
/* Unsupported logical segment type */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
|
|
|
|
return;
|
|
|
|
|
|
|
|
} /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case CI_DATA_SEGMENT:
|
|
|
|
|
|
|
|
/* Data segment, determin the logical type */
|
|
|
|
|
|
|
|
switch( segment_type )
|
|
|
|
{
|
|
|
|
case CI_DATA_SEG_SIMPLE:
|
|
|
|
|
|
|
|
/* Simple data segment */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
ds_item = proto_tree_add_text( path_tree, NULL, 0, 0, "Simple Data Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(ds_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree */
|
|
|
|
ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
|
|
|
|
|
|
|
|
/* Segment size */
|
|
|
|
seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
|
|
|
|
proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
|
|
|
|
|
|
|
|
/* Segment data */
|
|
|
|
if( seg_size != 0 )
|
|
|
|
{
|
|
|
|
qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
|
|
|
|
|
|
|
|
for( i=0; i < seg_size/2; i ++ )
|
|
|
|
{
|
|
|
|
temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
|
|
|
|
proto_item_append_text(qi, " 0x%04X", temp_word );
|
|
|
|
}
|
|
|
|
|
|
|
|
proto_item_set_len(qi, seg_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
proto_item_set_len( ds_item, 2 + seg_size );
|
|
|
|
pathpos = pathpos + 2 + seg_size;
|
|
|
|
|
|
|
|
proto_item_append_text(epath_item, "[Data]" );
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CI_DATA_SEG_SYMBOL:
|
|
|
|
|
|
|
|
/* ANSI extended symbol segment */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
ds_item = proto_tree_add_text( path_tree, NULL, 0, 0, "Extended Symbol Segment (0x%02X)", segment_type );
|
|
|
|
PROTO_ITEM_SET_GENERATED(ds_item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Create a sub tree */
|
|
|
|
ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
|
|
|
|
|
|
|
|
/* Segment size */
|
|
|
|
seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
it = proto_tree_add_text( ds_tree, NULL, 0, 0, "Data Size: %d", seg_size );
|
|
|
|
PROTO_ITEM_SET_GENERATED(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Segment data */
|
|
|
|
if( seg_size != 0 )
|
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( generate )
|
|
|
|
{
|
|
|
|
qi = proto_tree_add_text( ds_tree, NULL, 0, 0, "Data: %s",
|
|
|
|
tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
|
|
|
|
PROTO_ITEM_SET_GENERATED(qi);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2, seg_size, "Data: %s",
|
|
|
|
tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
proto_item_append_text(epath_item, "%s", tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
|
2009-06-26 02:38:23 +00:00
|
|
|
|
2008-05-15 01:44:53 +00:00
|
|
|
hidden_item = proto_tree_add_item( ds_tree, hf_cip_symbol, tvb, offset + pathpos + 2, seg_size, FALSE );
|
|
|
|
PROTO_ITEM_SET_HIDDEN(hidden_item);
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
if( seg_size %2 )
|
|
|
|
{
|
|
|
|
/* We have a PAD BYTE */
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( !generate )
|
|
|
|
proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2 + seg_size, 1, "Pad Byte (0x%02X)",
|
|
|
|
tvb_get_guint8( tvb, offset + pathpos + 2 + seg_size ) );
|
2004-09-23 17:34:35 +00:00
|
|
|
seg_size++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( !generate )
|
|
|
|
proto_item_set_len( ds_item, 2 + seg_size );
|
2004-09-23 17:34:35 +00:00
|
|
|
pathpos = pathpos + 2 + seg_size;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
|
|
|
|
return;
|
|
|
|
|
|
|
|
} /* End of switch sub-type */
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CI_NETWORK_SEGMENT:
|
|
|
|
|
|
|
|
/* Network segment -Determine the segment sub-type */
|
|
|
|
|
|
|
|
switch( segment_type & CI_NETWORK_SEG_TYPE_MASK )
|
|
|
|
{
|
|
|
|
case CI_NETWORK_SEG_SCHEDULE:
|
|
|
|
net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Schedule" );
|
|
|
|
net_tree = proto_item_add_subtree( net_item, ett_port_path );
|
|
|
|
|
|
|
|
proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Multiplier/Phase: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CI_NETWORK_SEG_FIXED_TAG:
|
|
|
|
net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Fixed Tag" );
|
|
|
|
net_tree = proto_item_add_subtree( net_item, ett_port_path );
|
|
|
|
|
|
|
|
proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Fixed Tag: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CI_NETWORK_SEG_PROD_INHI:
|
|
|
|
net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Production Inhibit" );
|
|
|
|
net_tree = proto_item_add_subtree( net_item, ett_port_path );
|
|
|
|
|
|
|
|
proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Production Inhibit Time: %dms", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
|
|
|
|
|
|
|
|
/* 2 bytes of path used */
|
|
|
|
pathpos += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
|
|
|
|
return;
|
|
|
|
|
|
|
|
} /* End of switch sub-type */
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
/* Unsupported segment type */
|
|
|
|
proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
|
|
|
|
return;
|
|
|
|
|
|
|
|
} /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
|
|
|
|
|
|
|
|
/* Next path segment */
|
|
|
|
if( pathpos < path_length )
|
|
|
|
proto_item_append_text( epath_item, ", " );
|
|
|
|
|
|
|
|
} /* end of while( pathpos < path_length ) */
|
|
|
|
|
|
|
|
} /* end of dissect_epath() */
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/************************************************
|
|
|
|
*
|
|
|
|
* Dissector for generic CIP object
|
|
|
|
*
|
|
|
|
************************************************/
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
static void
|
2009-06-26 02:38:23 +00:00
|
|
|
dissect_cip_generic_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo, proto_item *ti )
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_item *pi, *temp_item;
|
|
|
|
proto_tree *cmd_data_tree;
|
|
|
|
int req_path_size;
|
2004-09-23 17:34:35 +00:00
|
|
|
unsigned char add_stat_size;
|
2009-06-26 02:38:23 +00:00
|
|
|
unsigned char i;
|
2007-02-22 03:21:26 +00:00
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( tvb_get_guint8( tvb, offset ) & 0x80 )
|
2009-06-19 06:15:52 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Response message */
|
|
|
|
add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* If there is any command specific data create a sub-tree for it */
|
|
|
|
if( ( item_length-4-add_stat_size ) != 0 )
|
|
|
|
{
|
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
|
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PROTO_ITEM_SET_HIDDEN( ti );
|
|
|
|
}
|
2009-06-19 06:15:52 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
} /* End of if reply */
|
|
|
|
else
|
2009-06-19 06:15:52 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Request message */
|
2009-06-19 06:15:52 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add service to info column */
|
2004-09-23 17:34:35 +00:00
|
|
|
if(check_col(pinfo->cinfo, COL_INFO))
|
|
|
|
{
|
2007-12-10 03:12:11 +00:00
|
|
|
col_append_str( pinfo->cinfo, COL_INFO,
|
2009-06-26 02:38:23 +00:00
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals , "Unknown Service (0x%02x)") );
|
2004-09-23 17:34:35 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
|
2009-06-19 06:15:52 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* If there is any command specific data creat a sub-tree for it */
|
|
|
|
if( (item_length-req_path_size-2) != 0 )
|
2008-08-25 20:41:05 +00:00
|
|
|
{
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
|
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
|
2009-06-19 05:45:40 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Check what service code that recived */
|
|
|
|
|
|
|
|
if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Get attribute list request */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
int att_count;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add number of services */
|
|
|
|
att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add Attribute List */
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
|
2007-08-23 09:26:01 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
for( i=0; i < att_count; i++ )
|
2008-08-25 20:41:05 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
if( i == (att_count-1) )
|
|
|
|
proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
else
|
|
|
|
proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
} /* End of Get attribute list request */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
|
|
|
|
} /* End of check service code */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PROTO_ITEM_SET_HIDDEN( ti );
|
|
|
|
} /* End of if command-specific data present */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
} /* End of if-else( request ) */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
} /* End of dissect_cip_generic_data() */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
static int
|
|
|
|
dissect_cip_class_generic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
|
|
|
proto_item *ti;
|
|
|
|
proto_tree *class_tree;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( tree )
|
|
|
|
{
|
|
|
|
/* Create display subtree for the protocol */
|
|
|
|
ti = proto_tree_add_item(tree, proto_cip_class_generic, tvb, 0, -1, FALSE);
|
|
|
|
class_tree = proto_item_add_subtree( ti, ett_cip_class_generic );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
dissect_cip_generic_data( class_tree, tvb, 0, tvb_length(tvb), pinfo, ti );
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
return tvb_length(tvb);
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/************************************************
|
|
|
|
*
|
|
|
|
* Dissector for CIP Message Router
|
|
|
|
*
|
|
|
|
************************************************/
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
static void
|
|
|
|
dissect_cip_mr_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
|
|
|
|
{
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
typedef struct mr_mult_req_info {
|
|
|
|
guint8 service;
|
|
|
|
int num_services;
|
|
|
|
cip_req_info_t *requests;
|
|
|
|
} mr_mult_req_info_t;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_item *pi, *rrsc_item, *temp_item, *temp_item2;
|
|
|
|
proto_tree *temp_tree, *rrsc_tree, *cmd_data_tree;
|
|
|
|
int req_path_size;
|
|
|
|
int i;
|
|
|
|
unsigned char gen_status;
|
|
|
|
unsigned char add_stat_size;
|
|
|
|
int num_services, serv_offset;
|
|
|
|
unsigned char service;
|
|
|
|
mr_mult_req_info_t *mr_mult_req_info;
|
|
|
|
cip_req_info_t *mr_single_req_info;
|
|
|
|
cip_req_info_t *cip_req_info;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-08-09 06:47:24 +00:00
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP MR");
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add Service code & Request/Response tree */
|
|
|
|
rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
|
|
|
|
rrsc_tree = proto_item_add_subtree( rrsc_item, ett_mr_rrsc );
|
2009-06-19 06:15:52 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add Request/Response */
|
|
|
|
proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* watch for service collisions */
|
|
|
|
service = tvb_get_guint8( tvb, offset );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_item_append_text( rrsc_item, "%s (%s)",
|
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals, "Unknown Service (0x%02x)"),
|
2009-06-26 02:38:23 +00:00
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
|
|
|
|
cip_sc_rr, "") );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add Service code */
|
|
|
|
proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( tvb_get_guint8( tvb, offset ) & 0x80 )
|
|
|
|
{
|
|
|
|
gen_status = tvb_get_guint8( tvb, offset+2 );
|
|
|
|
add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* If there is any command specific data create a sub-tree for it */
|
|
|
|
if( ( item_length-4-add_stat_size ) != 0 )
|
|
|
|
{
|
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
|
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_mr_cmd_data );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
|
|
|
|
{
|
|
|
|
/* Success responses */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
|
|
|
/* Multiple Service Reply (Success)*/
|
|
|
|
|
|
|
|
/* Add number of replies */
|
|
|
|
num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
|
|
|
|
|
|
|
|
/* Add replies */
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
cip_req_info = (cip_req_info_t*)p_get_proto_data( pinfo->fd, proto_cip );
|
|
|
|
mr_mult_req_info = NULL;
|
|
|
|
if ( cip_req_info )
|
|
|
|
{
|
|
|
|
mr_mult_req_info = (mr_mult_req_info_t*)cip_req_info->pData;
|
|
|
|
|
|
|
|
if ( mr_mult_req_info
|
|
|
|
&& ( mr_mult_req_info->service != SC_MULT_SERV_PACK
|
|
|
|
|| mr_mult_req_info->num_services != num_services
|
|
|
|
)
|
|
|
|
)
|
|
|
|
mr_mult_req_info = NULL;
|
|
|
|
}
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
for( i=0; i < num_services; i++ )
|
|
|
|
{
|
|
|
|
int serv_length;
|
2009-06-26 02:38:23 +00:00
|
|
|
tvbuff_t *next_tvb;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
|
|
|
|
|
|
|
|
if( i == (num_services-1) )
|
|
|
|
{
|
|
|
|
/* Last service to add */
|
|
|
|
proto_item_append_text(temp_item, "%d", serv_offset );
|
|
|
|
serv_length = item_length-add_stat_size-serv_offset-4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
proto_item_append_text(temp_item, "%d, ", serv_offset );
|
|
|
|
serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_tree = proto_item_add_subtree( temp_item2, ett_mr_mult_ser );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
** We call our selves again to disect embedded packet
|
|
|
|
*/
|
|
|
|
|
2009-09-24 20:21:23 +00:00
|
|
|
col_append_str( pinfo->cinfo, COL_INFO, ", ");
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
next_tvb = tvb_new_subset(tvb, offset+serv_offset+4, serv_length, serv_length);
|
|
|
|
if ( mr_mult_req_info )
|
|
|
|
{
|
|
|
|
mr_single_req_info = mr_mult_req_info->requests + i;
|
|
|
|
dissect_cip_data( temp_tree, next_tvb, 0, pinfo, mr_single_req_info );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dissect_cip_data( temp_tree, next_tvb, 0, pinfo, NULL );
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
}
|
|
|
|
} /* End if Multiple service Packet */
|
|
|
|
else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
|
|
|
|
{
|
|
|
|
/* Get Attribute List Reply (Success)*/
|
|
|
|
|
|
|
|
int att_count;
|
|
|
|
|
|
|
|
/* Add Attribute Count */
|
|
|
|
att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
|
|
|
|
|
|
|
|
/* Add the data */
|
2009-06-26 02:38:23 +00:00
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
|
|
|
|
|
|
|
|
} /* End if GetAttrList */
|
2004-09-23 17:34:35 +00:00
|
|
|
else
|
2008-08-25 20:41:05 +00:00
|
|
|
{
|
|
|
|
/* Add data */
|
2009-06-26 02:38:23 +00:00
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
2008-08-25 20:41:05 +00:00
|
|
|
} /* end of check service code */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2008-08-25 20:41:05 +00:00
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Error responses */
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
} /* end of if-else( CI_CRC_SUCCESS ) */
|
|
|
|
|
|
|
|
} /* End of if command-specific data present */
|
|
|
|
|
2008-08-25 20:41:05 +00:00
|
|
|
} /* End of if reply */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Request message */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Add service to info column */
|
|
|
|
if(check_col(pinfo->cinfo, COL_INFO))
|
|
|
|
{
|
2007-12-10 03:12:11 +00:00
|
|
|
col_append_str( pinfo->cinfo, COL_INFO,
|
2004-09-23 17:34:35 +00:00
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals, "Unknown Service (0x%02x)") );
|
2004-09-23 17:34:35 +00:00
|
|
|
}
|
|
|
|
|
2008-08-25 20:41:05 +00:00
|
|
|
/* Add path size to tree */
|
|
|
|
req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* If there is any command specific data creat a sub-tree for it */
|
|
|
|
if( (item_length-req_path_size-2) != 0 )
|
|
|
|
{
|
|
|
|
|
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
|
2009-06-26 02:38:23 +00:00
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_mr_cmd_data );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Check what service code that recived */
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Multiple service packet */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add number of services */
|
|
|
|
num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add services */
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
cip_req_info = (cip_req_info_t*)p_get_proto_data( pinfo->fd, proto_cip );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
mr_mult_req_info = NULL;
|
|
|
|
if ( cip_req_info )
|
|
|
|
{
|
|
|
|
if ( cip_req_info->pData == NULL )
|
|
|
|
{
|
|
|
|
mr_mult_req_info = se_alloc(sizeof(mr_mult_req_info_t));
|
|
|
|
mr_mult_req_info->service = SC_MULT_SERV_PACK;
|
|
|
|
mr_mult_req_info->num_services = num_services;
|
|
|
|
mr_mult_req_info->requests = se_alloc(sizeof(cip_req_info_t)*num_services);
|
|
|
|
cip_req_info->pData = mr_mult_req_info;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mr_mult_req_info = (mr_mult_req_info_t*)cip_req_info->pData;
|
|
|
|
if ( mr_mult_req_info && mr_mult_req_info->num_services != num_services )
|
|
|
|
mr_mult_req_info = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for( i=0; i < num_services; i++ )
|
|
|
|
{
|
|
|
|
int serv_length;
|
|
|
|
tvbuff_t *next_tvb;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( i == (num_services-1) )
|
|
|
|
{
|
|
|
|
/* Last service to add */
|
|
|
|
serv_length = item_length-2-req_path_size-serv_offset;
|
|
|
|
proto_item_append_text(temp_item, "%d", serv_offset );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
|
|
|
|
proto_item_append_text(temp_item, "%d, ", serv_offset );
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
|
|
|
|
temp_tree = proto_item_add_subtree( temp_item2, ett_mr_mult_ser );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/*
|
|
|
|
** We call our selves again to disect embedded packet
|
|
|
|
*/
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-09-24 20:21:23 +00:00
|
|
|
col_append_str( pinfo->cinfo, COL_INFO, ", ");
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
next_tvb = tvb_new_subset(tvb, offset+serv_offset+6, serv_length, serv_length);
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if ( mr_mult_req_info )
|
|
|
|
{
|
|
|
|
mr_single_req_info = mr_mult_req_info->requests + i;
|
|
|
|
mr_single_req_info->bService = 0;
|
|
|
|
mr_single_req_info->dissector = NULL;
|
|
|
|
mr_single_req_info->IOILen = 0;
|
|
|
|
mr_single_req_info->pIOI = NULL;
|
|
|
|
mr_single_req_info->pData = NULL;
|
|
|
|
|
|
|
|
dissect_cip_data( temp_tree, next_tvb, 0, pinfo, mr_single_req_info );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dissect_cip_data( temp_tree, next_tvb, 0, pinfo, NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* End if Multiple service Packet */
|
|
|
|
else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
|
|
|
|
{
|
|
|
|
/* Get attribute list request */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
int att_count;
|
2009-06-19 05:45:40 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add number of services */
|
|
|
|
att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
|
|
|
|
|
|
|
|
/* Add Attribute List */
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
|
|
|
|
|
|
|
|
for( i=0; i < att_count; i++ )
|
|
|
|
{
|
|
|
|
if( i == (att_count-1) )
|
|
|
|
proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
else
|
|
|
|
proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* End of Get attribute list request */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
|
|
|
|
} /* End of check service code */
|
|
|
|
|
|
|
|
} /* End of if command-specific data present */
|
|
|
|
|
|
|
|
} /* End of if-else( request ) */
|
|
|
|
|
|
|
|
} /* End of dissect_cip_mr() */
|
|
|
|
|
|
|
|
static int
|
|
|
|
dissect_cip_class_mr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
|
|
|
proto_item *ti;
|
|
|
|
proto_tree *class_tree;
|
|
|
|
|
|
|
|
if( tree )
|
|
|
|
{
|
|
|
|
/* Create display subtree for the protocol */
|
|
|
|
ti = proto_tree_add_item(tree, proto_cip_class_mr, tvb, 0, -1, FALSE);
|
|
|
|
class_tree = proto_item_add_subtree( ti, ett_cip_class_mr );
|
|
|
|
|
|
|
|
dissect_cip_mr_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
|
|
|
|
}
|
|
|
|
|
|
|
|
return tvb_length(tvb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
*
|
|
|
|
* Dissector for CIP Connection Manager
|
|
|
|
*
|
|
|
|
************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
|
|
|
|
{
|
|
|
|
proto_item *pi, *rrsc_item, *ncppi, *ar_item, *temp_item;
|
|
|
|
proto_tree *temp_tree, *rrsc_tree, *ncp_tree, *cmd_data_tree;
|
|
|
|
int req_path_size, conn_path_size, temp_data;
|
|
|
|
unsigned char gen_status;
|
|
|
|
unsigned char add_stat_size;
|
|
|
|
unsigned short add_status;
|
|
|
|
unsigned char temp_byte, route_path_size;
|
|
|
|
unsigned char app_rep_size, i;
|
|
|
|
int msg_req_siz;
|
|
|
|
unsigned char service;
|
|
|
|
cip_req_info_t *preq_info;
|
|
|
|
cip_req_info_t *pembedded_req_info;
|
|
|
|
|
|
|
|
/* Special handling for Unconnected send response. If successful, embedded service code is sent.
|
|
|
|
* If failed, it can be either an Unconnected send response or the embedded service code response. */
|
|
|
|
preq_info = (cip_req_info_t*)p_get_proto_data( pinfo->fd, proto_cip );
|
|
|
|
if ( preq_info && ( tvb_get_guint8( tvb, offset ) & 0x80 )
|
|
|
|
&& preq_info->bService == SC_CM_UNCON_SEND
|
|
|
|
)
|
|
|
|
{
|
|
|
|
gen_status = tvb_get_guint8( tvb, offset+2 );
|
|
|
|
add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
|
|
|
|
if ( add_stat_size == 2 )
|
|
|
|
add_status = tvb_get_letohs( tvb, offset + 4 );
|
|
|
|
else
|
|
|
|
add_status = 0;
|
|
|
|
if( gen_status == 0 /* success response ) */
|
|
|
|
|| ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) != SC_CM_UNCON_SEND )
|
|
|
|
|| !( ( gen_status == 0x01 && ( add_status == 0x0204 || add_status == 0x0311 || add_status == 0x0312 || add_status == 0x0315 ) )
|
|
|
|
|| gen_status == 0x02
|
|
|
|
|| gen_status == 0x04
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
pembedded_req_info = (cip_req_info_t*)preq_info->pData;
|
|
|
|
|
|
|
|
if ( pembedded_req_info )
|
|
|
|
{
|
|
|
|
tvbuff_t *next_tvb;
|
|
|
|
void *p_save_proto_data;
|
|
|
|
|
|
|
|
p_save_proto_data = p_get_proto_data( pinfo->fd, proto_cip );
|
|
|
|
p_remove_proto_data(pinfo->fd, proto_cip);
|
|
|
|
p_add_proto_data(pinfo->fd, proto_cip, pembedded_req_info );
|
|
|
|
|
|
|
|
rrsc_item = proto_tree_add_text( item_tree, NULL, 0, 0, "(Service: Unconnected Send (Response))" );
|
|
|
|
next_tvb = tvb_new_subset(tvb, offset, item_length, item_length);
|
|
|
|
if ( pembedded_req_info && pembedded_req_info->dissector )
|
|
|
|
call_dissector(pembedded_req_info->dissector, next_tvb, pinfo, item_tree );
|
|
|
|
else
|
|
|
|
call_dissector( cip_class_generic_handle, next_tvb, pinfo, item_tree );
|
|
|
|
|
|
|
|
p_remove_proto_data(pinfo->fd, proto_cip);
|
|
|
|
p_add_proto_data(pinfo->fd, proto_cip, p_save_proto_data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-09 06:47:24 +00:00
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP CM");
|
2009-06-26 02:38:23 +00:00
|
|
|
|
|
|
|
/* Add Service code & Request/Response tree */
|
|
|
|
rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
|
|
|
|
rrsc_tree = proto_item_add_subtree( rrsc_item, ett_cm_rrsc );
|
|
|
|
|
|
|
|
/* Add Request/Response */
|
|
|
|
proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
|
|
|
|
|
|
|
|
/* watch for service collisions */
|
|
|
|
service = tvb_get_guint8( tvb, offset );
|
|
|
|
proto_item_append_text( rrsc_item, "%s (%s)",
|
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals_cm , "Unknown Service (0x%02x)"),
|
2009-06-26 02:38:23 +00:00
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
|
|
|
|
cip_sc_rr, "") );
|
|
|
|
|
|
|
|
/* Add Service code */
|
|
|
|
proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
|
|
|
|
|
|
|
|
if( tvb_get_guint8( tvb, offset ) & 0x80 )
|
|
|
|
{
|
|
|
|
/* Response message */
|
|
|
|
gen_status = tvb_get_guint8( tvb, offset+2 );
|
|
|
|
add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
|
|
|
|
|
|
|
|
/* If there is any command specific data create a sub-tree for it */
|
|
|
|
if( ( item_length-4-add_stat_size ) != 0 )
|
|
|
|
{
|
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
|
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_cm_cmd_data );
|
|
|
|
|
|
|
|
if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
|
|
|
|
{
|
|
|
|
/* Success responses */
|
|
|
|
|
|
|
|
if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_OPEN )
|
|
|
|
{
|
|
|
|
/* Forward open Response (Success) */
|
|
|
|
guint32 O2TConnID;
|
|
|
|
guint32 T2OConnID;
|
|
|
|
guint16 ConnSerialNumber;
|
|
|
|
guint32 DeviceSerialNumber;
|
|
|
|
guint16 VendorID;
|
|
|
|
|
|
|
|
/* Display originator to target connection ID */
|
|
|
|
O2TConnID = tvb_get_letohl( tvb, offset+4+add_stat_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", O2TConnID );
|
|
|
|
|
|
|
|
/* Display target to originator connection ID */
|
|
|
|
T2OConnID = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", T2OConnID );
|
|
|
|
|
|
|
|
/* Display connection serial number */
|
|
|
|
ConnSerialNumber = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", ConnSerialNumber );
|
|
|
|
|
|
|
|
/* Display the originator vendor id */
|
|
|
|
VendorID = tvb_get_letohs( tvb, offset+4+add_stat_size+10 );
|
|
|
|
proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+10, 2, TRUE);
|
|
|
|
|
|
|
|
/* Display the originator serial number */
|
|
|
|
DeviceSerialNumber = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", DeviceSerialNumber );
|
|
|
|
|
|
|
|
/* Display originator to target actual packet interval */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+16, 4, "O->T API: %dms (0x%08X)", temp_data / 1000, temp_data );
|
|
|
|
|
|
|
|
/* Display originator to target actual packet interval */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+20, 4, "T->O API: %dms (0x%08X)", temp_data / 1000, temp_data );
|
|
|
|
|
|
|
|
/* Display the application reply size */
|
|
|
|
app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
|
|
|
|
|
|
|
|
/* Display the Reserved byte */
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
|
|
|
|
|
|
|
|
if( app_rep_size != 0 )
|
|
|
|
{
|
|
|
|
/* Display application Reply data */
|
|
|
|
ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
|
|
|
|
|
|
|
|
for( i=0; i < app_rep_size; i++ )
|
|
|
|
{
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
|
|
|
|
proto_item_append_text(ar_item, " 0x%02X", temp_byte );
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* End of if reply data */
|
|
|
|
|
|
|
|
enip_open_cip_connection( pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber, O2TConnID, T2OConnID );
|
|
|
|
|
|
|
|
} /* End of if forward open response */
|
|
|
|
else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_CLOSE )
|
|
|
|
{
|
|
|
|
/* Forward close response (Success) */
|
|
|
|
guint16 ConnSerialNumber;
|
|
|
|
guint32 DeviceSerialNumber;
|
|
|
|
guint16 VendorID;
|
|
|
|
|
|
|
|
/* Display connection serial number */
|
|
|
|
ConnSerialNumber = tvb_get_letohs( tvb, offset+4+add_stat_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", ConnSerialNumber );
|
|
|
|
|
|
|
|
/* Display the originator vendor id */
|
|
|
|
VendorID = tvb_get_letohs( tvb, offset+4+add_stat_size+2 );
|
|
|
|
proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
|
|
|
|
|
|
|
|
/* Display the originator serial number */
|
|
|
|
DeviceSerialNumber = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", DeviceSerialNumber );
|
|
|
|
|
|
|
|
/* Display the application reply size */
|
|
|
|
app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
|
|
|
|
|
|
|
|
/* Display the Reserved byte */
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
|
|
|
|
|
|
|
|
if( app_rep_size != 0 )
|
|
|
|
{
|
|
|
|
/* Display application Reply data */
|
|
|
|
ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
|
|
|
|
|
|
|
|
for( i=0; i < app_rep_size; i ++ )
|
|
|
|
{
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
|
|
|
|
proto_item_append_text(ar_item, " 0x%02X", temp_byte );
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* End of if reply data */
|
|
|
|
|
|
|
|
enip_close_cip_connection( pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber );
|
|
|
|
|
|
|
|
} /* End of if forward close response */
|
|
|
|
else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_UNCON_SEND )
|
|
|
|
{
|
|
|
|
/* Unconnected send response (Success) */
|
|
|
|
|
|
|
|
/* Display service response data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
|
|
|
}
|
|
|
|
else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
|
|
|
|
{
|
|
|
|
/* Get Attribute List Reply (Success)*/
|
|
|
|
|
|
|
|
int att_count;
|
|
|
|
|
|
|
|
/* Add Attribute Count */
|
|
|
|
att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
|
|
|
|
|
|
|
|
/* Add the data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
|
|
|
|
|
|
|
|
} /* Get Attribute List Reply */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
|
|
|
} /* end of check service code */
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Error responses */
|
|
|
|
|
|
|
|
if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_OPEN ) ||
|
|
|
|
( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_CLOSE ) )
|
|
|
|
{
|
|
|
|
/* Forward open and forward close error response look the same */
|
|
|
|
|
|
|
|
/* Display connection serial number */
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* Display the originator vendor id */
|
|
|
|
proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
|
|
|
|
|
|
|
|
/* Display the originator serial number */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
/* Display remaining path size */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
|
|
|
|
|
|
|
|
/* Display reserved data */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
|
|
|
|
}
|
|
|
|
else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_UNCON_SEND )
|
|
|
|
{
|
|
|
|
/* Unconnected send response (Unsuccess) */
|
|
|
|
|
|
|
|
/* Display remaining path size */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* end of if-else( CI_CRC_SUCCESS ) */
|
|
|
|
|
|
|
|
} /* End of if command-specific data present */
|
|
|
|
|
|
|
|
} /* End of if reply */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Request message */
|
|
|
|
|
|
|
|
/* Add service to info column */
|
|
|
|
if(check_col(pinfo->cinfo, COL_INFO))
|
|
|
|
{
|
|
|
|
col_append_str( pinfo->cinfo, COL_INFO,
|
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals_cm , "Unknown Service (0x%02x)") );
|
2009-06-26 02:38:23 +00:00
|
|
|
}
|
|
|
|
req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
|
|
|
|
|
|
|
|
/* If there is any command specific data creat a sub-tree for it */
|
|
|
|
if( (item_length-req_path_size-2) != 0 )
|
|
|
|
{
|
|
|
|
|
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
|
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_cm_cmd_data );
|
|
|
|
|
|
|
|
/* Check what service code that recived */
|
|
|
|
|
|
|
|
if( tvb_get_guint8( tvb, offset ) == SC_CM_FWD_OPEN )
|
|
|
|
{
|
|
|
|
/* Forward open Request*/
|
|
|
|
|
|
|
|
/* Display the priority/tick timer */
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
|
|
|
|
|
|
|
|
/* Display the time-out ticks */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
|
|
|
|
|
|
|
|
/* Display the actual time out */
|
|
|
|
temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
|
|
|
|
|
|
|
|
/* Display originator to taget connection ID */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
/* Display target to originator connection ID */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
/* Display connection serial number */
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* Display the originator vendor id */
|
|
|
|
proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+12, 2, TRUE);
|
|
|
|
|
|
|
|
/* Display the originator serial number */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
|
|
|
|
|
|
|
|
/* Display the timeout multiplier */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+18, 1, "Connection Timeout Multiplier: %s (%d)", val_to_str( temp_data, cip_con_time_mult_vals , "Reserved" ), temp_data );
|
|
|
|
|
|
|
|
/* Put out an indicator for the reserved bytes */
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
|
|
|
|
|
|
|
|
/* Display originator to target requested packet interval */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+22, 4, "O->T RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
|
|
|
|
|
|
|
|
/* Display originator to target network connection patameterts, in a tree */
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
|
|
|
|
ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+26, 2, "O->T Network Connection Parameters: 0x%04X", temp_data );
|
|
|
|
ncp_tree = proto_item_add_subtree(ncppi, ett_cm_ncp);
|
|
|
|
|
|
|
|
/* Add the data to the tree */
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_own,
|
|
|
|
tvb, offset+2+req_path_size+26, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_typ,
|
|
|
|
tvb, offset+2+req_path_size+26, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_prio,
|
|
|
|
tvb, offset+2+req_path_size+26, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_fixed_var,
|
|
|
|
tvb, offset+2+req_path_size+26, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_con_size,
|
|
|
|
tvb, offset+2+req_path_size+26, 2, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Display target to originator requested packet interval */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+28, 4, "T->O RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
|
|
|
|
|
2008-08-25 20:41:05 +00:00
|
|
|
/* Display target to originator network connection patameterts, in a tree */
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
|
|
|
|
ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+32, 2, "T->O Network Connection Parameters: 0x%04X", temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
ncp_tree = proto_item_add_subtree(ncppi, ett_cm_ncp);
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Add the data to the tree */
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_own,
|
|
|
|
tvb, offset+2+req_path_size+32, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_typ,
|
|
|
|
tvb, offset+2+req_path_size+32, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_prio,
|
|
|
|
tvb, offset+2+req_path_size+32, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_fixed_var,
|
|
|
|
tvb, offset+2+req_path_size+32, 2, TRUE );
|
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_con_size,
|
|
|
|
tvb, offset+2+req_path_size+32, 2, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Transport type/trigger in tree*/
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
|
|
|
|
|
2008-08-25 20:41:05 +00:00
|
|
|
ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
|
2009-06-26 02:38:23 +00:00
|
|
|
ncp_tree = proto_item_add_subtree(ncppi, ett_cm_ncp);
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Add the data to the tree */
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_dir,
|
|
|
|
tvb, offset+2+req_path_size+34, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_trigg,
|
|
|
|
tvb, offset+2+req_path_size+34, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_class,
|
|
|
|
tvb, offset+2+req_path_size+34, 1, TRUE );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Add path size */
|
|
|
|
conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
|
|
|
|
|
|
|
|
/* Add the epath */
|
|
|
|
pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
|
2009-06-26 02:38:23 +00:00
|
|
|
dissect_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size, FALSE );
|
2004-09-23 17:34:35 +00:00
|
|
|
}
|
2009-06-26 02:38:23 +00:00
|
|
|
else if( tvb_get_guint8( tvb, offset ) == SC_CM_FWD_CLOSE )
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
|
|
|
/* Forward Close Request */
|
|
|
|
|
|
|
|
/* Display the priority/tick timer */
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
|
|
|
|
|
|
|
|
/* Display the time-out ticks */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
|
|
|
|
|
|
|
|
/* Display the actual time out */
|
|
|
|
temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
|
|
|
|
|
|
|
|
/* Display connection serial number */
|
|
|
|
temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
|
|
|
|
|
|
|
|
/* Display the originator vendor id */
|
|
|
|
proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+4, 2, TRUE);
|
|
|
|
|
|
|
|
/* Display the originator serial number */
|
|
|
|
temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add the path size */
|
|
|
|
conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
|
|
|
|
|
|
|
|
/* Add the reserved byte */
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
|
|
|
|
|
|
|
|
/* Add the EPATH */
|
|
|
|
pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
|
|
|
|
dissect_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size, FALSE );
|
|
|
|
|
|
|
|
} /* End of forward close */
|
|
|
|
else if( tvb_get_guint8( tvb, offset ) == SC_CM_UNCON_SEND )
|
|
|
|
{
|
|
|
|
/* Unconnected send */
|
|
|
|
tvbuff_t *next_tvb;
|
|
|
|
|
|
|
|
/* Display the priority/tick timer */
|
|
|
|
temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
|
|
|
|
|
|
|
|
/* Display the time-out ticks */
|
|
|
|
temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
|
|
|
|
|
|
|
|
/* Display the actual time out */
|
|
|
|
temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
|
|
|
|
|
|
|
|
/* Message request size */
|
|
|
|
msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
|
|
|
|
|
|
|
|
/* Message Request */
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
|
|
|
|
temp_tree = proto_item_add_subtree(temp_item, ett_cm_mes_req );
|
|
|
|
|
|
|
|
/*
|
|
|
|
** We call our selves again to disect embedded packet
|
|
|
|
*/
|
|
|
|
|
2009-09-24 20:21:23 +00:00
|
|
|
col_append_str( pinfo->cinfo, COL_INFO, ": ");
|
2009-06-26 02:38:23 +00:00
|
|
|
|
|
|
|
next_tvb = tvb_new_subset(tvb, offset+2+req_path_size+4, msg_req_siz, msg_req_siz);
|
|
|
|
preq_info = p_get_proto_data( pinfo->fd, proto_cip );
|
|
|
|
pembedded_req_info = NULL;
|
|
|
|
if ( preq_info )
|
|
|
|
{
|
|
|
|
if ( preq_info->pData == NULL )
|
|
|
|
{
|
|
|
|
pembedded_req_info = (cip_req_info_t*)se_alloc(sizeof(cip_req_info_t));
|
|
|
|
pembedded_req_info->bService = 0;
|
|
|
|
pembedded_req_info->dissector = NULL;
|
|
|
|
pembedded_req_info->IOILen = 0;
|
|
|
|
pembedded_req_info->pIOI = NULL;
|
|
|
|
pembedded_req_info->pData = NULL;
|
|
|
|
preq_info->pData = pembedded_req_info;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pembedded_req_info = (cip_req_info_t*)preq_info->pData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dissect_cip_data( temp_tree, next_tvb, 0, pinfo, pembedded_req_info );
|
|
|
|
|
|
|
|
if( msg_req_siz % 2 )
|
|
|
|
{
|
|
|
|
/* Pad byte */
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
|
|
|
|
tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
|
|
|
|
msg_req_siz++; /* include the padding */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Route Path Size */
|
|
|
|
route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Route Path Size: %d (words)", route_path_size/2 );
|
|
|
|
|
|
|
|
/* Reserved */
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
|
|
|
|
tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
|
|
|
|
|
|
|
|
/* Route Path */
|
|
|
|
temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path: ");
|
|
|
|
dissect_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size, FALSE );
|
|
|
|
} /* End if unconnected send */
|
|
|
|
else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
|
|
|
|
{
|
|
|
|
/* Get attribute list request */
|
|
|
|
|
|
|
|
int att_count;
|
|
|
|
|
|
|
|
/* Add number of services */
|
|
|
|
att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
|
|
|
|
|
|
|
|
/* Add Attribute List */
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
|
|
|
|
|
|
|
|
for( i=0; i < att_count; i++ )
|
|
|
|
{
|
|
|
|
if( i == (att_count-1) )
|
|
|
|
proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
else
|
|
|
|
proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* End of Get attribute list request */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
|
|
|
|
} /* End of check service code */
|
|
|
|
|
|
|
|
} /* End of if command-specific data present */
|
|
|
|
|
|
|
|
} /* End of if-else( request ) */
|
|
|
|
|
|
|
|
} /* End of dissect_cip_cm_data() */
|
|
|
|
|
|
|
|
static int
|
|
|
|
dissect_cip_class_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
|
|
|
proto_item *ti;
|
|
|
|
proto_tree *class_tree;
|
|
|
|
|
|
|
|
if( tree )
|
|
|
|
{
|
|
|
|
/* Create display subtree for the protocol */
|
|
|
|
ti = proto_tree_add_item(tree, proto_cip_class_cm, tvb, 0, -1, FALSE);
|
|
|
|
class_tree = proto_item_add_subtree( ti, ett_cip_class_cm );
|
|
|
|
|
|
|
|
dissect_cip_cm_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
|
|
|
|
}
|
|
|
|
|
|
|
|
return tvb_length(tvb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
*
|
|
|
|
* Dissector for CIP Connection Configuration Object
|
|
|
|
*
|
|
|
|
************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_cip_cco_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
|
|
|
|
{
|
|
|
|
proto_item *pi, *rrsc_item, *temp_item;
|
|
|
|
proto_tree *rrsc_tree, *cmd_data_tree;
|
|
|
|
int req_path_size, temp_data;
|
|
|
|
unsigned char gen_status;
|
|
|
|
unsigned char add_stat_size;
|
|
|
|
unsigned char i;
|
|
|
|
|
2009-08-09 06:47:24 +00:00
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP CCO");
|
2009-06-26 02:38:23 +00:00
|
|
|
|
|
|
|
/* Add Service code & Request/Response tree */
|
|
|
|
rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
|
|
|
|
rrsc_tree = proto_item_add_subtree( rrsc_item, ett_cco_rrsc );
|
|
|
|
|
|
|
|
/* Add Request/Response */
|
|
|
|
proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
|
|
|
|
|
|
|
|
proto_item_append_text( rrsc_item, "%s (%s)",
|
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals_cco , "Unknown Service (0x%02x)"),
|
2009-06-26 02:38:23 +00:00
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
|
|
|
|
cip_sc_rr, "") );
|
|
|
|
|
|
|
|
/* Add Service code */
|
|
|
|
proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
|
|
|
|
|
|
|
|
if( tvb_get_guint8( tvb, offset ) & 0x80 )
|
|
|
|
{
|
|
|
|
/* Response message */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add additional status size */
|
|
|
|
gen_status = tvb_get_guint8( tvb, offset+2 );
|
|
|
|
add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* If there is any command specific data create a sub-tree for it */
|
|
|
|
if( ( item_length-4-add_stat_size ) != 0 )
|
|
|
|
{
|
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
|
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_cco_cmd_data );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Success responses */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
|
|
|
}
|
|
|
|
else
|
2004-09-23 17:34:35 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Error responses */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add data */
|
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
|
|
|
|
} /* end of if-else( CI_CRC_SUCCESS ) */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
} /* End of if command-specific data present */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
} /* End of if reply */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Request message */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Add service to info column */
|
|
|
|
if(check_col(pinfo->cinfo, COL_INFO))
|
|
|
|
{
|
|
|
|
col_append_str( pinfo->cinfo, COL_INFO,
|
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals_cco , "Unknown Service (0x%02x)") );
|
2009-06-26 02:38:23 +00:00
|
|
|
}
|
|
|
|
req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* If there is any command specific data creat a sub-tree for it */
|
|
|
|
if( (item_length-req_path_size-2) != 0 )
|
|
|
|
{
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
|
|
|
|
cmd_data_tree = proto_item_add_subtree( pi, ett_cco_cmd_data );
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Check what service code that recived */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if( tvb_get_guint8( tvb, offset ) == SC_CCO_AUDIT_CHANGE )
|
|
|
|
{
|
|
|
|
/* Audit Change */
|
2009-06-19 05:45:40 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_data = tvb_get_letohs( tvb, offset+2+req_path_size );
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Change Type: ");
|
|
|
|
|
|
|
|
if (temp_data == 0)
|
|
|
|
proto_item_append_text(temp_item, "Full" );
|
|
|
|
else if (temp_data == 1)
|
|
|
|
proto_item_append_text(temp_item, "Incremental" );
|
|
|
|
else
|
|
|
|
proto_item_append_text(temp_item, "Reserved" );
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
|
|
|
|
{
|
|
|
|
/* Get attribute list request */
|
|
|
|
|
|
|
|
int att_count;
|
|
|
|
|
|
|
|
/* Add number of services */
|
|
|
|
att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
|
|
|
|
proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
|
|
|
|
|
|
|
|
/* Add Attribute List */
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
|
|
|
|
|
|
|
|
for( i=0; i < att_count; i++ )
|
|
|
|
{
|
|
|
|
if( i == (att_count-1) )
|
|
|
|
proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
else
|
|
|
|
proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* End of Get attribute list request */
|
2009-06-26 02:38:23 +00:00
|
|
|
else if ( tvb_get_guint8( tvb, offset ) == SC_CCO_CHANGE_COMPLETE )
|
|
|
|
{
|
|
|
|
/* Change complete request */
|
2007-08-23 09:26:01 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
temp_data = tvb_get_letohs( tvb, offset+2+req_path_size );
|
|
|
|
temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Change Type: ");
|
2007-02-22 03:21:26 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
if (temp_data == 0)
|
|
|
|
proto_item_append_text(temp_item, "Full" );
|
|
|
|
else if (temp_data == 1)
|
|
|
|
proto_item_append_text(temp_item, "Incremental" );
|
|
|
|
else
|
|
|
|
proto_item_append_text(temp_item, "Reserved" );
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
else
|
|
|
|
{
|
2008-08-25 20:41:05 +00:00
|
|
|
/* Add data */
|
2009-06-26 02:38:23 +00:00
|
|
|
add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
|
2004-09-23 17:34:35 +00:00
|
|
|
} /* End of check service code */
|
|
|
|
|
|
|
|
} /* End of if command-specific data present */
|
|
|
|
|
2008-08-25 20:41:05 +00:00
|
|
|
} /* End of if-else( request ) */
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
} /* End of dissect_cip_cco_data() */
|
|
|
|
|
|
|
|
static int
|
|
|
|
dissect_cip_class_cco(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
|
|
|
proto_item *ti;
|
|
|
|
proto_tree *class_tree;
|
|
|
|
|
|
|
|
if( tree )
|
|
|
|
{
|
|
|
|
/* Create display subtree for the protocol */
|
|
|
|
ti = proto_tree_add_item(tree, proto_cip_class_cco, tvb, 0, -1, FALSE);
|
|
|
|
class_tree = proto_item_add_subtree( ti, ett_cip_class_cco );
|
|
|
|
|
|
|
|
dissect_cip_cco_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
|
|
|
|
}
|
|
|
|
|
|
|
|
return tvb_length(tvb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
*
|
|
|
|
* Dissector for CIP Request/Response
|
|
|
|
* - matches requests/responses
|
|
|
|
* - calls class specific dissector
|
|
|
|
*
|
|
|
|
************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info *pinfo, cip_req_info_t* preq_info )
|
|
|
|
{
|
|
|
|
proto_item *ti;
|
|
|
|
proto_tree *cip_tree;
|
|
|
|
proto_item *pi, *rrsc_item, *status_item;
|
|
|
|
proto_tree *rrsc_tree, *status_tree;
|
|
|
|
int req_path_size;
|
|
|
|
unsigned char gen_status;
|
|
|
|
unsigned char add_stat_size;
|
|
|
|
unsigned char i;
|
|
|
|
guint32 classid;
|
|
|
|
unsigned char service,ioilen,segment;
|
|
|
|
void *p_save_proto_data;
|
|
|
|
dissector_handle_t dissector;
|
|
|
|
|
|
|
|
p_save_proto_data = p_get_proto_data(pinfo->fd, proto_cip);
|
|
|
|
p_remove_proto_data(pinfo->fd, proto_cip);
|
|
|
|
p_add_proto_data(pinfo->fd, proto_cip, preq_info);
|
|
|
|
|
|
|
|
/* Create display subtree for the protocol */
|
|
|
|
ti = proto_tree_add_item(item_tree, proto_cip, tvb, 0, -1, FALSE);
|
|
|
|
cip_tree = proto_item_add_subtree( ti, ett_cip );
|
|
|
|
|
|
|
|
/* Add Service code & Request/Response tree */
|
|
|
|
rrsc_item = proto_tree_add_text( cip_tree, tvb, offset, 1, "Service: " );
|
|
|
|
rrsc_tree = proto_item_add_subtree( rrsc_item, ett_rrsc );
|
|
|
|
|
|
|
|
/* Add Request/Response */
|
|
|
|
proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
|
|
|
|
|
|
|
|
/* watch for service collisions */
|
|
|
|
service = tvb_get_guint8( tvb, offset );
|
|
|
|
proto_item_append_text( rrsc_item, "%s (%s)",
|
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
2009-07-06 13:59:09 +00:00
|
|
|
cip_sc_vals , "Unknown Service (0x%02x)"),
|
2009-06-26 02:38:23 +00:00
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
|
|
|
|
cip_sc_rr, "") );
|
|
|
|
|
|
|
|
/* Add Service code */
|
|
|
|
proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
|
|
|
|
|
|
|
|
if( service & 0x80 )
|
|
|
|
{
|
|
|
|
/* Response message */
|
|
|
|
status_item = proto_tree_add_text( cip_tree, tvb, offset+2, 1, "Status: " );
|
|
|
|
status_tree = proto_item_add_subtree( status_item, ett_status_item );
|
|
|
|
|
|
|
|
/* Add general status */
|
|
|
|
gen_status = tvb_get_guint8( tvb, offset+2 );
|
|
|
|
proto_tree_add_item(status_tree, hf_cip_genstat, tvb, offset+2, 1, TRUE );
|
|
|
|
proto_item_append_text( status_item, "%s", val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
|
|
|
|
cip_gs_vals , "Unknown Response (%x)") );
|
|
|
|
|
|
|
|
/* Add reply status to info column */
|
|
|
|
if(check_col(pinfo->cinfo, COL_INFO))
|
|
|
|
{
|
|
|
|
col_append_str( pinfo->cinfo, COL_INFO,
|
|
|
|
val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
|
|
|
|
cip_gs_vals , "Unknown Response (%x)") );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add additional status size */
|
|
|
|
proto_tree_add_text( status_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)",
|
|
|
|
tvb_get_guint8( tvb, offset+3 ) );
|
|
|
|
|
|
|
|
add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
|
|
|
|
|
|
|
|
if( add_stat_size )
|
|
|
|
{
|
|
|
|
proto_item_append_text( status_item, ", Extended:" );
|
|
|
|
|
|
|
|
/* Add additional status */
|
|
|
|
pi = proto_tree_add_text( status_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
|
|
|
|
|
|
|
|
for( i=0; i < add_stat_size/2; i ++ )
|
|
|
|
{
|
|
|
|
proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
|
|
|
|
proto_item_append_text( status_item, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
proto_item_set_len( status_item, 2 + add_stat_size );
|
|
|
|
|
|
|
|
|
|
|
|
if( preq_info
|
|
|
|
&& !( preq_info->bService == ( service & 0x7F )
|
|
|
|
|| ( preq_info->bService == SC_CM_UNCON_SEND && preq_info->dissector == cip_class_cm_handle )
|
|
|
|
)
|
|
|
|
)
|
|
|
|
preq_info = NULL;
|
|
|
|
|
|
|
|
if ( preq_info )
|
|
|
|
{
|
|
|
|
if ( preq_info->IOILen && preq_info->pIOI )
|
|
|
|
{
|
|
|
|
tvbuff_t* tvbIOI;
|
|
|
|
|
|
|
|
tvbIOI = tvb_new_real_data( preq_info->pIOI, preq_info->IOILen * 2, preq_info->IOILen * 2);
|
|
|
|
if ( tvbIOI )
|
|
|
|
{
|
|
|
|
/* pi = add_byte_array_text_to_proto_tree( cip_tree, tvbIOI, 0, req_path_size+1, "IOI: " );
|
|
|
|
PROTO_ITEM_SET_GENERATED(pi); */
|
|
|
|
|
|
|
|
pi = proto_tree_add_text( cip_tree, NULL, 0, 0, "Request Path Size: %d (words)", preq_info->IOILen );
|
|
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
|
|
|
|
|
|
|
/* Add the epath */
|
|
|
|
pi = proto_tree_add_text(cip_tree, NULL, 0, 0, "Request Path: ");
|
|
|
|
PROTO_ITEM_SET_GENERATED(pi);
|
2009-09-22 05:49:15 +00:00
|
|
|
dissect_epath( tvbIOI, pi, 0, preq_info->IOILen*2, TRUE );
|
2009-06-26 02:38:23 +00:00
|
|
|
tvb_free(tvbIOI);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( preq_info && preq_info->dissector )
|
|
|
|
{
|
|
|
|
call_dissector( preq_info->dissector, tvb, pinfo, item_tree );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
call_dissector( cip_class_generic_handle, tvb, pinfo, item_tree );
|
|
|
|
}
|
|
|
|
} /* End of if reply */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Request message */
|
|
|
|
|
|
|
|
/* Add path size to tree */
|
|
|
|
req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
|
|
|
|
proto_tree_add_text( cip_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
|
|
|
|
|
|
|
|
/* Add the epath */
|
|
|
|
pi = proto_tree_add_text(cip_tree, tvb, offset+2, req_path_size, "Request Path: ");
|
|
|
|
dissect_epath( tvb, pi, offset+2, req_path_size, FALSE );
|
|
|
|
|
|
|
|
/* parse IOI; extract class ID */
|
|
|
|
ioilen = tvb_get_guint8( tvb, offset + 1 );
|
|
|
|
if ( preq_info )
|
|
|
|
preq_info->dissector = NULL;
|
|
|
|
dissector = NULL;
|
|
|
|
if ( ioilen >= 1 )
|
|
|
|
{
|
|
|
|
segment = tvb_get_guint8( tvb, offset + 2 );
|
|
|
|
switch ( segment & CI_SEGMENT_TYPE_MASK )
|
|
|
|
{
|
|
|
|
case CI_LOGICAL_SEGMENT:
|
|
|
|
/* Logical segment, determin the logical type */
|
|
|
|
switch( segment & CI_LOGICAL_SEG_TYPE_MASK )
|
|
|
|
{
|
|
|
|
case CI_LOGICAL_SEG_CLASS_ID:
|
|
|
|
|
|
|
|
/* Logical Class ID, do a format check */
|
|
|
|
classid = 0;
|
|
|
|
switch ( segment & CI_LOGICAL_SEG_FORMAT_MASK )
|
|
|
|
{
|
|
|
|
case CI_LOGICAL_SEG_8_BIT:
|
|
|
|
classid = tvb_get_guint8( tvb, offset + 3 );
|
|
|
|
break;
|
|
|
|
case CI_LOGICAL_SEG_16_BIT:
|
|
|
|
if ( ioilen >= 2 )
|
|
|
|
classid = tvb_get_letohs( tvb, offset + 4 );
|
|
|
|
break;
|
|
|
|
case CI_LOGICAL_SEG_32_BIT:
|
|
|
|
if ( ioilen >= 3 )
|
|
|
|
classid = tvb_get_letohl( tvb, offset + 4 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dissector = dissector_get_port_handle( subdissector_class_table, classid );
|
|
|
|
if ( preq_info )
|
|
|
|
preq_info->dissector = dissector;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CI_DATA_SEGMENT:
|
|
|
|
dissector = dissector_get_port_handle( subdissector_symbol_table, segment );
|
|
|
|
if ( preq_info )
|
|
|
|
preq_info->dissector = dissector;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( preq_info )
|
|
|
|
{
|
|
|
|
/* copy IOI for access by response packet */
|
|
|
|
preq_info->pIOI = se_alloc( ioilen*2);
|
2010-01-25 11:47:39 +00:00
|
|
|
preq_info->IOILen = ioilen;
|
|
|
|
tvb_memcpy(tvb, preq_info->pIOI, offset+2, ioilen*2);
|
2009-06-26 02:38:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( preq_info )
|
|
|
|
preq_info->bService = service;
|
|
|
|
|
|
|
|
if ( dissector )
|
|
|
|
{
|
|
|
|
call_dissector( dissector, tvb, pinfo, item_tree );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
call_dissector( cip_class_generic_handle, tvb, pinfo, item_tree );
|
|
|
|
}
|
|
|
|
} /* End of if-else( request ) */
|
|
|
|
|
|
|
|
p_remove_proto_data(pinfo->fd, proto_cip);
|
|
|
|
p_add_proto_data(pinfo->fd, proto_cip, p_save_proto_data);
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
} /* End of dissect_cip_data() */
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
enip_request_info_t *enip_info;
|
|
|
|
cip_req_info_t *preq_info;
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Make entries in Protocol column and Info column on summary display */
|
2009-08-09 06:47:24 +00:00
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP");
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-08-09 07:36:13 +00:00
|
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Each CIP request received by ENIP gets a unique ID */
|
|
|
|
enip_info = (enip_request_info_t*)p_get_proto_data(pinfo->fd, proto_enip);
|
|
|
|
|
|
|
|
if ( enip_info )
|
2009-06-19 05:45:40 +00:00
|
|
|
{
|
2009-06-26 02:38:23 +00:00
|
|
|
preq_info = (cip_req_info_t*)enip_info->cip_info;
|
|
|
|
if ( preq_info == NULL )
|
|
|
|
{
|
|
|
|
preq_info = se_alloc( sizeof( cip_req_info_t ) );
|
2010-01-25 11:47:39 +00:00
|
|
|
preq_info->bService = 0;
|
|
|
|
preq_info->dissector = NULL;
|
|
|
|
preq_info->IOILen = 0;
|
|
|
|
preq_info->pIOI = NULL;
|
|
|
|
preq_info->pData = NULL;
|
|
|
|
enip_info->cip_info = preq_info;
|
2009-06-26 02:38:23 +00:00
|
|
|
}
|
|
|
|
dissect_cip_data( tree, tvb, 0, pinfo, enip_info->cip_info );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dissect_cip_data( tree, tvb, 0, pinfo, NULL );
|
2004-09-23 17:34:35 +00:00
|
|
|
}
|
2009-06-19 06:15:52 +00:00
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
return tvb_length(tvb);
|
|
|
|
}
|
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/*
|
|
|
|
* Protocol initialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
cip_init_protocol(void)
|
|
|
|
{
|
|
|
|
proto_enip = proto_get_id_by_filter_name( "enip" );
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
proto_register_cip(void)
|
|
|
|
{
|
|
|
|
/* Setup list of header fields */
|
2008-08-25 20:41:05 +00:00
|
|
|
static hf_register_info hf[] = {
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
{ &hf_cip_rr,
|
|
|
|
{ "Request/Response", "cip.rr",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
|
|
|
|
"Request or Response message", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_sc,
|
|
|
|
{ "Service", "cip.sc",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
|
|
|
|
"Service Code", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_epath,
|
|
|
|
{ "EPath", "cip.epath",
|
|
|
|
FT_BYTES, BASE_NONE, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_genstat,
|
|
|
|
{ "General Status", "cip.genstat",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_gs_vals), 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_port,
|
|
|
|
{ "Port", "cip.port",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0,
|
|
|
|
"Port Identifier", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_link_address_byte,
|
|
|
|
{ "Link Address", "cip.linkaddress",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_link_address_string,
|
|
|
|
{ "Link Address", "cip.linkaddress",
|
|
|
|
FT_STRING, BASE_NONE, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_class8,
|
|
|
|
{ "Class", "cip.class",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_class_names_vals), 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_class16,
|
|
|
|
{ "Class", "cip.class",
|
|
|
|
FT_UINT16, BASE_HEX, VALS(cip_class_names_vals), 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_class32,
|
|
|
|
{ "Class", "cip.class",
|
|
|
|
FT_UINT32, BASE_HEX, VALS(cip_class_names_vals), 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_instance8,
|
|
|
|
{ "Instance", "cip.instance",
|
|
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_instance16,
|
|
|
|
{ "Instance", "cip.instance",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_instance32,
|
|
|
|
{ "Instance", "cip.instance",
|
|
|
|
FT_UINT32, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_member8,
|
|
|
|
{ "Member", "cip.member",
|
|
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_member16,
|
|
|
|
{ "Member", "cip.member",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_member32,
|
|
|
|
{ "Member", "cip.member",
|
|
|
|
FT_UINT32, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_attribute8,
|
|
|
|
{ "Attribute", "cip.attribute",
|
|
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_attribute16,
|
|
|
|
{ "Attribute", "cip.attribute",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_attribute32,
|
|
|
|
{ "Attribute", "cip.attribute",
|
|
|
|
FT_UINT32, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_conpoint8,
|
|
|
|
{ "Connection Point", "cip.connpoint",
|
|
|
|
FT_UINT8, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_conpoint16,
|
|
|
|
{ "Connection Point", "cip.connpoint",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_conpoint32,
|
|
|
|
{ "Connection Point", "cip.connpoint",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_symbol,
|
|
|
|
{ "Symbol", "cip.symbol",
|
|
|
|
FT_STRING, BASE_NONE, NULL, 0,
|
|
|
|
"ANSI Extended Symbol Segment", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_vendor,
|
|
|
|
{ "Vendor ID", "cip.vendor",
|
|
|
|
FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_devtype,
|
|
|
|
{ "Device Type", "cip.devtype",
|
|
|
|
FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
|
|
|
|
NULL, HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_fwo_comp,
|
|
|
|
{ "Compatibility", "cip.fwo.cmp",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80,
|
|
|
|
"EKey: Compatibility bit", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_fwo_mrev,
|
|
|
|
{ "Major Revision", "cip.fwo.major",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x7F,
|
|
|
|
"EKey: Major Revision", HFILL }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static hf_register_info hf_cm[] = {
|
|
|
|
{ &hf_cip_cm_rr,
|
|
|
|
{ "Request/Response", "cip.rr",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
|
|
|
|
"Request or Response message", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_sc,
|
|
|
|
{ "Service", "cip.sc",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
|
|
|
|
"Service Code", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_comp,
|
|
|
|
{ "Compatibility", "cip.cm.fwo.cmp",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80,
|
|
|
|
"Fwd Open: Compatibility bit", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_mrev,
|
|
|
|
{ "Major Revision", "cip.cm.fwo.major",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x7F,
|
|
|
|
"Fwd Open: Major Revision", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_con_size,
|
|
|
|
{ "Connection Size", "cip.cm.fwo.consize",
|
|
|
|
FT_UINT16, BASE_DEC, NULL, 0x01FF,
|
|
|
|
"Fwd Open: Connection size", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_fixed_var,
|
|
|
|
{ "Connection Size Type", "cip.cm.fwo.f_v",
|
|
|
|
FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200,
|
|
|
|
"Fwd Open: Fixed or variable connection size", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_prio,
|
|
|
|
{ "Priority", "cip.cm.fwo.prio",
|
|
|
|
FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00,
|
|
|
|
"Fwd Open: Connection priority", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_typ,
|
|
|
|
{ "Connection Type", "cip.cm.fwo.type",
|
|
|
|
FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000,
|
|
|
|
"Fwd Open: Connection type", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_own,
|
|
|
|
{ "Owner", "cip.cm.fwo.owner",
|
|
|
|
FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000,
|
|
|
|
"Fwd Open: Redundant owner bit", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_dir,
|
|
|
|
{ "Direction", "cip.cm.fwo.dir",
|
|
|
|
FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), 0x80,
|
|
|
|
"Fwd Open: Direction", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_trigg,
|
|
|
|
{ "Trigger", "cip.cm.fwo.trigger",
|
|
|
|
FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), 0x70,
|
|
|
|
"Fwd Open: Production trigger", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cm_fwo_class,
|
|
|
|
{ "Class", "cip.cm.fwo.transport",
|
|
|
|
FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), 0x0F,
|
|
|
|
"Fwd Open: Transport Class", HFILL }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static hf_register_info hf_mr[] = {
|
|
|
|
{ &hf_cip_mr_rr,
|
|
|
|
{ "Request/Response", "cip.rr",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
|
|
|
|
"Request or Response message", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_mr_sc,
|
|
|
|
{ "Service", "cip.sc",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
|
|
|
|
"Service Code", HFILL }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static hf_register_info hf_cco[] = {
|
|
|
|
{ &hf_cip_cco_rr,
|
|
|
|
{ "Request/Response", "cip.rr",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
|
|
|
|
"Request or Response message", HFILL }
|
|
|
|
},
|
|
|
|
{ &hf_cip_cco_sc,
|
|
|
|
{ "Service", "cip.sc",
|
|
|
|
FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
|
|
|
|
"Service Code", HFILL }
|
|
|
|
}
|
2004-09-23 17:34:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Setup protocol subtree array */
|
2009-06-26 02:38:23 +00:00
|
|
|
static gint *ett[] = {
|
|
|
|
&ett_cip_class_generic,
|
|
|
|
&ett_cip,
|
|
|
|
&ett_path,
|
|
|
|
&ett_ekey_path,
|
|
|
|
&ett_rrsc,
|
|
|
|
&ett_mcsc,
|
|
|
|
&ett_cia_path,
|
|
|
|
&ett_data_seg,
|
|
|
|
&ett_cmd_data,
|
|
|
|
&ett_port_path,
|
|
|
|
&ett_status_item
|
|
|
|
};
|
|
|
|
|
|
|
|
static gint *ett_mr[] = {
|
|
|
|
&ett_cip_class_mr,
|
|
|
|
&ett_mr_rrsc,
|
|
|
|
&ett_mr_mult_ser,
|
|
|
|
&ett_mr_cmd_data
|
|
|
|
};
|
|
|
|
|
|
|
|
static gint *ett_cm[] = {
|
|
|
|
&ett_cip_class_cm,
|
|
|
|
&ett_cm_rrsc,
|
|
|
|
&ett_cm_mes_req,
|
|
|
|
&ett_cm_ncp,
|
|
|
|
&ett_cm_cmd_data
|
|
|
|
};
|
|
|
|
|
|
|
|
static gint *ett_cco[] = {
|
|
|
|
&ett_cip_class_cco,
|
|
|
|
&ett_cco_rrsc,
|
|
|
|
&ett_cco_cmd_data
|
|
|
|
};
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Register the protocol name and description */
|
|
|
|
proto_cip = proto_register_protocol("Common Industrial Protocol",
|
2009-06-26 02:38:23 +00:00
|
|
|
"CIP", "cip");
|
2004-09-23 17:34:35 +00:00
|
|
|
|
|
|
|
/* Required function calls to register the header fields and subtrees used */
|
2008-08-25 20:41:05 +00:00
|
|
|
proto_register_field_array(proto_cip, hf, array_length(hf));
|
|
|
|
proto_register_subtree_array(ett, array_length(ett));
|
2009-06-26 02:38:23 +00:00
|
|
|
subdissector_class_table = register_dissector_table("cip.class.iface",
|
|
|
|
"CIP Class Interface Handle", FT_UINT32, BASE_HEX);
|
|
|
|
subdissector_symbol_table = register_dissector_table("cip.data_segment.iface",
|
|
|
|
"CIP Data Segment Interface Handle", FT_UINT32, BASE_HEX);
|
|
|
|
|
|
|
|
/* Register the protocol name and description */
|
|
|
|
proto_cip_class_generic = proto_register_protocol("CIP Class Generic",
|
|
|
|
"CIPCLS", "cipcls");
|
2004-09-23 17:34:35 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Register the protocol name and description */
|
|
|
|
proto_cip_class_mr = proto_register_protocol("CIP Message Router",
|
|
|
|
"CIPMR", "cipmr");
|
|
|
|
proto_register_field_array(proto_cip_class_mr, hf_mr, array_length(hf_mr));
|
|
|
|
proto_register_subtree_array(ett_mr, array_length(ett_mr));
|
|
|
|
|
|
|
|
proto_cip_class_cm = proto_register_protocol("CIP Connection Manager",
|
|
|
|
"CIPCM", "cipcm");
|
|
|
|
proto_register_field_array(proto_cip_class_cm, hf_cm, array_length(hf_cm));
|
|
|
|
proto_register_subtree_array(ett_cm, array_length(ett_cm));
|
|
|
|
|
|
|
|
proto_cip_class_cco = proto_register_protocol("CIP Connection Configuration Object",
|
|
|
|
"CIPCCO", "cipcco");
|
|
|
|
proto_register_field_array(proto_cip_class_cco, hf_cco, array_length(hf_cco));
|
|
|
|
proto_register_subtree_array(ett_cco, array_length(ett_cco));
|
|
|
|
|
|
|
|
register_init_routine(&cip_init_protocol);
|
2004-09-23 17:34:35 +00:00
|
|
|
} /* end of proto_register_cip() */
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
proto_reg_handoff_cip(void)
|
|
|
|
{
|
|
|
|
/* Create dissector handles */
|
2009-06-19 06:15:52 +00:00
|
|
|
/* Register for UCMM CIP data, using EtherNet/IP SendRRData service*/
|
|
|
|
/* Register for Connected CIP data, using EtherNet/IP SendUnitData service*/
|
2009-06-26 02:38:23 +00:00
|
|
|
cip_handle = new_create_dissector_handle( dissect_cip, proto_cip );
|
|
|
|
dissector_add( "enip.srrd.iface", ENIP_CIP_INTERFACE, cip_handle );
|
2009-06-19 06:15:52 +00:00
|
|
|
dissector_add( "enip.sud.iface", ENIP_CIP_INTERFACE, cip_handle );
|
2009-06-19 05:45:40 +00:00
|
|
|
|
2009-06-26 02:38:23 +00:00
|
|
|
/* Create and register dissector handle for generic class */
|
|
|
|
cip_class_generic_handle = new_create_dissector_handle( dissect_cip_class_generic, proto_cip_class_generic );
|
|
|
|
dissector_add( "cip.class.iface", 0, cip_class_generic_handle );
|
|
|
|
|
|
|
|
/* Create and register dissector handle for Message Router */
|
|
|
|
cip_class_mr_handle = new_create_dissector_handle( dissect_cip_class_mr, proto_cip_class_mr );
|
|
|
|
dissector_add( "cip.class.iface", CI_CLS_MR, cip_class_mr_handle );
|
|
|
|
|
|
|
|
/* Create and register dissector handle for Connection Manager */
|
|
|
|
cip_class_cm_handle = new_create_dissector_handle( dissect_cip_class_cm, proto_cip_class_cm );
|
|
|
|
dissector_add( "cip.class.iface", CI_CLS_CM, cip_class_cm_handle );
|
|
|
|
|
|
|
|
/* Create and register dissector handle for Connection Configuration Object */
|
|
|
|
cip_class_cco_handle = new_create_dissector_handle( dissect_cip_class_cco, proto_cip_class_cco );
|
|
|
|
dissector_add( "cip.class.iface", CI_CLS_CCO, cip_class_cco_handle );
|
|
|
|
|
2004-09-23 17:34:35 +00:00
|
|
|
} /* end of proto_reg_handoff_cip() */
|