2 * Routines for Common Industrial Protocol (CIP) dissection
3 * CIP Home: www.odva.org
6 * Magnus Hansson <mah@hms.se>
7 * Joakim Wiberg <jow@hms.se>
9 * Added support for Connection Configuration Object
10 * ryan wamsley * Copyright 2007
12 * Object dependend services based on IOI
13 * Jan Bartels, Siempelkamp Maschinen- und Anlagenbau GmbH & Co. KG
18 * Wireshark - Network traffic analyzer
19 * By Gerald Combs <gerald@wireshark.org>
20 * Copyright 1998 Gerald Combs
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version 2
25 * of the License, or (at your option) any later version.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 &ett_path, dissect_epath
40 &ett_ekey_path, dissect_epath
41 &ett_mcsc, dissect_epath,
42 &ett_cia_path, dissect_epath
43 &ett_data_seg, dissect_epath
44 &ett_port_path, dissect_epath
45 &ett_rrsc, dissect_cip_generic_data, dissect_cip_mr_data, dissect_cip_cm_data, dissect_cip_cco_data, dissect_cip_pccc_data
46 &ett_status_item dissect_cip_generic_data, dissect_cip_mr_data, dissect_cip_cm_data, dissect_cip_cco_data, dissect_cip_pccc_data
48 &ett_cmd_data, dissect_cip_generic_data, dissect_cip_mr_data, dissect_cip_cm_data, dissect_cip_cco_data, dissect_cip_pccc_data
49 &ett_ncp, dissect_cip_cm_data
50 &ett_mes_req, dissect_cip_cm_data
51 &ett_mult_ser, dissect_cip_mr_data
64 #include <epan/packet.h>
65 #include "packet-enip.h"
66 #include "packet-cip.h"
68 #define ENIP_CIP_INTERFACE 0
70 typedef struct cip_req_info {
71 dissector_handle_t dissector;
78 dissector_handle_t cip_handle;
79 dissector_handle_t cip_class_generic_handle,cip_class_cm_handle,cip_class_mr_handle;
80 dissector_handle_t cip_class_cco_handle;
82 /* Initialize the protocol and registered fields */
83 static int proto_cip = -1;
84 static int proto_cip_class_generic = -1;
85 static int proto_cip_class_cm = -1;
86 static int proto_cip_class_mr = -1;
87 static int proto_cip_class_cco = -1;
88 static int proto_enip = -1;
90 static int hf_cip_sc = -1;
91 static int hf_cip_rr = -1;
92 static int hf_cip_epath = -1;
93 static int hf_cip_genstat = -1;
95 static int hf_cip_fwo_comp = -1;
96 static int hf_cip_fwo_mrev = -1;
98 static int hf_cip_cm_sc = -1;
99 static int hf_cip_cm_rr = -1;
100 static int hf_cip_cm_fwo_comp = -1;
101 static int hf_cip_cm_fwo_mrev = -1;
102 static int hf_cip_cm_fwo_con_size = -1;
103 static int hf_cip_cm_fwo_fixed_var = -1;
104 static int hf_cip_cm_fwo_prio = -1;
105 static int hf_cip_cm_fwo_typ = -1;
106 static int hf_cip_cm_fwo_own = -1;
107 static int hf_cip_cm_fwo_dir = -1;
108 static int hf_cip_cm_fwo_trigg = -1;
109 static int hf_cip_cm_fwo_class = -1;
111 static int hf_cip_vendor = -1;
112 static int hf_cip_devtype = -1;
113 static int hf_cip_port = -1;
114 static int hf_cip_link_address_byte = -1;
115 static int hf_cip_link_address_string = -1;
116 static int hf_cip_class8 = -1;
117 static int hf_cip_class16 = -1;
118 static int hf_cip_class32 = -1;
119 static int hf_cip_instance8 = -1;
120 static int hf_cip_instance16 = -1;
121 static int hf_cip_instance32 = -1;
122 static int hf_cip_member8 = -1;
123 static int hf_cip_member16 = -1;
124 static int hf_cip_member32 = -1;
125 static int hf_cip_attribute8 = -1;
126 static int hf_cip_attribute16 = -1;
127 static int hf_cip_attribute32 = -1;
128 static int hf_cip_conpoint8 = -1;
129 static int hf_cip_conpoint16 = -1;
130 static int hf_cip_conpoint32 = -1;
131 static int hf_cip_symbol = -1;
133 static int hf_cip_mr_sc = -1;
134 static int hf_cip_mr_rr = -1;
136 static int hf_cip_cco_sc = -1;
137 static int hf_cip_cco_rr = -1;
139 /* Initialize the subtree pointers */
140 static gint ett_cip = -1;
141 static gint ett_cip_class_generic = -1;
142 static gint ett_cip_class_mr = -1;
143 static gint ett_cip_class_cm = -1;
144 static gint ett_cip_class_cco = -1;
146 static gint ett_path = -1;
147 static gint ett_ekey_path = -1;
148 static gint ett_mcsc = -1;
149 static gint ett_cia_path = -1;
150 static gint ett_data_seg = -1;
151 static gint ett_port_path = -1;
153 static gint ett_rrsc = -1;
154 static gint ett_status_item = -1;
155 static gint ett_cmd_data = -1;
157 static gint ett_cm_rrsc = -1;
158 static gint ett_cm_ncp = -1;
159 static gint ett_cm_mes_req = -1;
160 static gint ett_cm_cmd_data = -1;
162 static gint ett_mr_rrsc = -1;
163 static gint ett_mr_mult_ser = -1;
164 static gint ett_mr_cmd_data = -1;
166 static gint ett_cco_rrsc = -1;
167 static gint ett_cco_cmd_data = -1;
169 static dissector_table_t subdissector_class_table;
170 static dissector_table_t subdissector_symbol_table;
172 /* Translate function to string - CIP Service codes */
173 static const value_string cip_sc_vals[] = {
179 /* Translate function to string - CIP Service codes for CM */
180 static const value_string cip_sc_vals_cm[] = {
183 /* Some class specific services */
184 { SC_CM_FWD_CLOSE, "Forward Close" },
185 { SC_CM_FWD_OPEN, "Forward Open" },
186 { SC_CM_UNCON_SEND, "Unconnected Send" },
191 /* Translate function to string - CIP Service codes for CCO */
192 static const value_string cip_sc_vals_cco[] = {
195 /* Some class specific services */
196 { SC_CCO_KICK_TIMER, "Kick Timer" },
197 { SC_CCO_OPEN_CONN, "Open Connection" },
198 { SC_CCO_CLOSE_CONN, "Close Connection" },
199 { SC_CCO_STOP_CONN, "Stop Connection" },
200 { SC_CCO_CHANGE_START, "Change Start" },
201 { SC_CCO_GET_STATUS, "Get Status" },
202 { SC_CCO_CHANGE_COMPLETE, "Change Complete" },
203 { SC_CCO_AUDIT_CHANGE, "Audit Changes" },
208 /* Translate function to string - CIP Request/Response */
209 static const value_string cip_sc_rr[] = {
216 /* Translate function to string - Compatibility */
217 static const value_string cip_com_bit_vals[] = {
218 { 0, "Bit Cleared" },
224 /* Translate function to string - Connection priority */
225 static const value_string cip_con_prio_vals[] = {
226 { 0, "Low Priority" },
227 { 1, "High Priority" },
234 /* Translate function to string - Connection size fixed or variable */
235 static const value_string cip_con_fw_vals[] = {
242 /* Translate function to string - Connection owner */
243 static const value_string cip_con_owner_vals[] = {
250 /* Translate function to string - Connection direction */
251 static const value_string cip_con_dir_vals[] = {
258 /* Translate function to string - Production trigger */
259 static const value_string cip_con_trigg_vals[] = {
261 { 1, "Change-Of-State" },
262 { 2, "Application Object" },
267 /* Translate function to string - Transport class */
268 static const value_string cip_con_class_vals[] = {
277 /* Translate function to string - Connection type */
278 static const value_string cip_con_type_vals[] = {
281 { 2, "Point to Point" },
287 /* Translate function to string - Timeout Multiplier */
288 static const value_string cip_con_time_mult_vals[] = {
301 /* Translate function to string - CIP General Status codes */
302 static const value_string cip_gs_vals[] = {
303 { CI_GRC_SUCCESS, "Success" },
304 { CI_GRC_FAILURE, "Connection failure" },
305 { CI_GRC_NO_RESOURCE, "Resource unavailable" },
306 { CI_GRC_BAD_DATA, "Invalid parameter value" },
307 { CI_GRC_BAD_PATH, "Path segment error" },
308 { CI_GRC_BAD_CLASS_INSTANCE, "Path destination unknown" },
309 { CI_GRC_PARTIAL_DATA, "Partial transfer" },
310 { CI_GRC_CONN_LOST, "Connection lost" },
311 { CI_GRC_BAD_SERVICE, "Service not supported" },
312 { CI_GRC_BAD_ATTR_DATA, "Invalid attribute value" },
313 { CI_GRC_ATTR_LIST_ERROR, "Attribute list error" },
314 { CI_GRC_ALREADY_IN_MODE, "Already in requested mode/state" },
315 { CI_GRC_BAD_OBJ_MODE, "Object state conflict" },
316 { CI_GRC_OBJ_ALREADY_EXISTS, "Object already exists" },
317 { CI_GRC_ATTR_NOT_SETTABLE, "Attribute not settable" },
318 { CI_GRC_PERMISSION_DENIED, "Privilege violation" },
319 { CI_GRC_DEV_IN_WRONG_STATE, "Device state conflict" },
320 { CI_GRC_REPLY_DATA_TOO_LARGE,"Reply data too large" },
321 { CI_GRC_FRAGMENT_PRIMITIVE, "Fragmentation of a primitive value" },
322 { CI_GRC_CONFIG_TOO_SMALL, "Not enough data" },
323 { CI_GRC_UNDEFINED_ATTR, "Attribute not supported" },
324 { CI_GRC_CONFIG_TOO_BIG, "Too much data" },
325 { CI_GRC_OBJ_DOES_NOT_EXIST, "Object does not exist" },
326 { CI_GRC_NO_FRAGMENTATION, "Service fragmentation sequence not in progress" },
327 { CI_GRC_DATA_NOT_SAVED, "No stored attribute data" },
328 { CI_GRC_DATA_WRITE_FAILURE, "Store operation failure" },
329 { CI_GRC_REQUEST_TOO_LARGE, "Routing failure, request packet too large" },
330 { CI_GRC_RESPONSE_TOO_LARGE, "Routing failure, response packet too large" },
331 { CI_GRC_MISSING_LIST_DATA, "Missing attribute list entry data" },
332 { CI_GRC_INVALID_LIST_STATUS, "Invalid attribute value list" },
333 { CI_GRC_SERVICE_ERROR, "Embedded service error" },
334 { CI_GRC_CONN_RELATED_FAILURE,"Vendor specific error" },
335 { CI_GRC_INVALID_PARAMETER, "Invalid parameter" },
336 { CI_GRC_WRITE_ONCE_FAILURE, "Write-once value or medium already written" },
337 { CI_GRC_INVALID_REPLY, "Invalid reply received" },
338 { CI_GRC_BUFFER_OVERFLOW, "Buffer overflow" },
339 { CI_GRC_MESSAGE_FORMAT, "Invalid message format" },
340 { CI_GRC_BAD_KEY_IN_PATH, "Key failure in path" },
341 { CI_GRC_BAD_PATH_SIZE, "Path size invalid" },
342 { CI_GRC_UNEXPECTED_ATTR, "Unexpected attribute in list" },
343 { CI_GRC_INVALID_MEMBER, "Invalid Member ID" },
344 { CI_GRC_MEMBER_NOT_SETTABLE, "Member not settable" },
345 { CI_GRC_G2_SERVER_FAILURE, "Group 2 only server general failure" },
346 { CI_GRC_UNKNOWN_MB_ERROR, "Unknown Modbus error" },
351 /* Translate Vendor ID:s */
352 const value_string cip_vendor_vals[] = {
358 /* Translate Device Profile:s */
359 const value_string cip_devtype_vals[] = {
360 { DP_GEN_DEV, "Generic Device" },
361 { DP_AC_DRIVE, "AC Drive" },
362 { DP_MOTOR_OVERLOAD, "Motor Overload" },
363 { DP_LIMIT_SWITCH, "Limit Switch" },
364 { DP_IND_PROX_SWITCH, "Inductive Proximity Switch" },
365 { DP_PHOTO_SENSOR, "Photoelectric Sensor" },
366 { DP_GENP_DISC_IO, "General Purpose Discrete I/O"},
367 { DP_RESOLVER, "Resolver" },
368 { DP_COM_ADAPTER, "Communications Adapter" },
369 { DP_POS_CNT, "Position Controller", },
370 { DP_DC_DRIVE, "DC Drive" },
371 { DP_CONTACTOR, "Contactor", },
372 { DP_MOTOR_STARTER, "Motor Starter", },
373 { DP_SOFT_START, "Soft Start", },
374 { DP_HMI, "Human-Machine Interface" },
375 { DP_MASS_FLOW_CNT, "Mass Flow Controller" },
376 { DP_PNEUM_VALVE, "Pneumatic Valve" },
377 { DP_VACUUM_PRES_GAUGE, "Vacuum Pressure Gauge" },
382 #define CI_CLS_MR 0x02 /* Message Router */
383 #define CI_CLS_CM 0x06 /* Connection Manager */
384 #define CI_CLS_CCO 0xF3 /* Connection Configuration Object */
386 /* Translate class names */
387 static const value_string cip_class_names_vals[] = {
388 { 0x01, "Identity Object" },
389 { 0x02, "Message Router" },
390 { 0x03, "DeviceNet Object" },
391 { 0x04, "Assembly Object" },
392 { 0x05, "Connection Object" },
393 { 0x06, "Connection Manager" },
394 { 0x07, "Register Object" },
395 { 0x08, "Discrete Input Point Object" },
396 { 0x09, "Discrete Output Point Object" },
397 { 0x0A, "Analog Input Point Object" },
398 { 0x0B, "Analog Output Point Object" },
399 { 0x0E, "Presence Sensing Object" },
400 { 0x0F, "Parameter Object" },
401 { 0x10, "Parameter Group Object" },
402 { 0x12, "Group Object" },
403 { 0x1D, "Discrete Input Group Object" },
404 { 0x1E, "Discrete Output Group Object" },
405 { 0x1F, "Discrete Group Object" },
406 { 0x20, "Analog Input Group Object" },
407 { 0x21, "Analog Output Group Object" },
408 { 0x22, "Analog Group Object" },
409 { 0x23, "Position Sensor Object" },
410 { 0x24, "Position Controller Supervisor Object" },
411 { 0x25, "Position Controller Object" },
412 { 0x26, "Block Sequencer Object" },
413 { 0x27, "Command Block Object" },
414 { 0x28, "Motor Data Object" },
415 { 0x29, "Control Supervisor Object" },
416 { 0x2A, "AC/DC Drive Object" },
417 { 0x2B, "Acknowledge Handler Object" },
418 { 0x2C, "Overload Object" },
419 { 0x2D, "Softstart Object" },
420 { 0x2E, "Selection Object" },
421 { 0x30, "S-Device Supervisor Object" },
422 { 0x31, "S-Analog Sensor Object" },
423 { 0x32, "S-Analog Actuator Object" },
424 { 0x33, "S-Single Stage Controller Object" },
425 { 0x34, "S-Gas Calibration Object" },
426 { 0x35, "Trip Point Object" },
427 { 0x37, "File Object" },
428 { 0x38, "S-Partial Pressure Object" },
429 { 0x39, "Safety Supervisor Object" },
430 { 0x3A, "Safety Validator Object" },
431 { 0x3B, "Safety Discrete Output Point Object" },
432 { 0x3C, "Safety Discrete Output Group Object" },
433 { 0x3D, "Safety Discrete Input Point Object" },
434 { 0x3E, "Safety Discrete Input Group Object" },
435 { 0x3F, "Safety Dual Channel Output Object" },
436 { 0x40, "S-Sensor Calibration Object" },
437 { 0x41, "Event Log Object" },
438 { 0x42, "Motion Axis Object" },
439 { 0x43, "Time Sync Object" },
440 { 0x44, "Modbus Object" },
441 { 0x45, "Originator Connection List Object" },
442 { 0x46, "Modbus Serial Link Object" },
443 { 0x47, "Device Level Ring (DLR) Object" },
444 { 0x48, "QoS Object" },
445 { 0xF0, "ControlNet Object" },
446 { 0xF1, "ControlNet Keeper Object" },
447 { 0xF2, "ControlNet Scheduling Object" },
448 { 0xF3, "Connection Configuration Object" },
449 { 0xF4, "Port Object" },
450 { 0xF5, "TCP/IP Interface Object" },
451 { 0xF6, "EtherNet Link Object" },
452 { 0xF7, "CompoNet Object" },
453 { 0xF8, "CompoNet Repeater Object" },
459 dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info *pinfo, cip_req_info_t *preq_info );
462 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
465 char *tmp2, *tmp2start;
467 int i,tmp_length,tmp2_length;
469 /* At least one version of Apple's C compiler/linker is buggy, causing
470 a complaint from the linker about the "literal C string section"
471 not ending with '\0' if we initialize a 16-element "char" array with
472 a 16-character string, the fact that initializing such an array with
473 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
474 '\0' byte in the string nonwithstanding. */
475 static const char my_hex_digits[16] =
476 { '0', '1', '2', '3', '4', '5', '6', '7',
477 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
480 if( ( length * 2 ) > 32 )
488 tmp2_length = ( length * 2 ) + 1;
491 tmp = tvb_get_ptr( tvb, start, tmp_length );
492 tmp2 = (char*)ep_alloc( tmp2_length );
496 for( i = 0; i < tmp_length; i++ )
500 *tmp2++ = my_hex_digits[octet&0xF];
502 *tmp2++ = my_hex_digits[octet&0xF];
505 if( tmp_length != length )
514 pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
518 } /* end of add_byte_array_text_to_proto_tree() */
523 dissect_epath( tvbuff_t *tvb, proto_item *epath_item, int offset, int path_length, gboolean generate )
525 int pathpos, temp_data, temp_data2, seg_size, i, temp_word;
526 unsigned char segment_type, opt_link_size;
527 proto_tree *path_tree, *port_tree, *net_tree;
528 proto_item *qi, *cia_item, *ds_item;
529 proto_tree *e_key_tree, *cia_tree, *ds_tree;
530 proto_item *mcpi, *port_item, *net_item;
533 proto_item *hidden_item;
535 /* Create a sub tree for the epath */
536 path_tree = proto_item_add_subtree( epath_item, ett_path );
540 hidden_item = proto_tree_add_item(path_tree, hf_cip_epath,
541 tvb, offset, path_length, TRUE );
542 PROTO_ITEM_SET_HIDDEN(hidden_item);
547 while( pathpos < path_length )
549 /* Get segement type */
550 segment_type = tvb_get_guint8( tvb, offset + pathpos );
552 /* Determine the segment type */
554 switch( segment_type & CI_SEGMENT_TYPE_MASK )
556 case CI_PORT_SEGMENT:
558 port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
561 port_item = proto_tree_add_text( path_tree, NULL, 0, 0, "Port Segment" );
562 PROTO_ITEM_SET_GENERATED(port_item);
565 port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
566 port_tree = proto_item_add_subtree( port_item, ett_port_path );
568 /* Add port number */
571 it = proto_tree_add_uint(port_tree, hf_cip_port, NULL, 0, 0, ( segment_type & 0x0F ) );
572 PROTO_ITEM_SET_GENERATED(it);
575 proto_tree_add_item( port_tree, hf_cip_port, tvb, offset + pathpos, 1, TRUE );
576 proto_item_append_text( epath_item, "Port: %d", ( segment_type & 0x0F ) );
577 proto_item_append_text( port_item, ": Port: %d", ( segment_type & 0x0F ) );
579 if( segment_type & 0x10 )
581 /* Add Extended Link Address flag */
584 it = proto_tree_add_text( port_tree, NULL, 0, 0, "Extended Link Address: TRUE" );
585 PROTO_ITEM_SET_GENERATED(it);
588 it = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: TRUE" );
590 /* Add size of extended link address */
591 opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
594 it = proto_tree_add_text( port_tree, NULL, 0, 0, "Link Address Size: %d", opt_link_size );
595 PROTO_ITEM_SET_GENERATED(it);
598 it = proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size );
600 /* Add extended link address */
603 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) );
604 PROTO_ITEM_SET_GENERATED(it);
607 proto_tree_add_item( port_tree, hf_cip_link_address_string, tvb, offset+pathpos+2, opt_link_size, FALSE );
608 proto_item_append_text( epath_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
609 proto_item_append_text( port_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
612 if( opt_link_size % 2 )
614 proto_item_set_len( port_item, 3 + opt_link_size );
615 pathpos = pathpos + 3 + opt_link_size;
619 proto_item_set_len( port_item, 2 + opt_link_size );
620 pathpos = pathpos + 2 + opt_link_size;
625 /* Add Extended Link Address flag */
628 it = proto_tree_add_text( port_tree, NULL, 0, 0, "Extended Link Address: FALSE" );
629 PROTO_ITEM_SET_GENERATED(it);
632 it = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: FALSE" );
634 /* Add Link Address */
637 it = proto_tree_add_uint(port_tree, hf_cip_link_address_byte, NULL, 0, 0, tvb_get_guint8( tvb, offset + pathpos + 1 ) );
638 PROTO_ITEM_SET_GENERATED(it);
641 proto_tree_add_item( port_tree, hf_cip_link_address_byte, tvb, offset+pathpos+1, 1, FALSE );
642 proto_item_append_text( epath_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
643 proto_item_append_text( port_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
645 proto_item_set_len( port_item, 2 );
651 case CI_LOGICAL_SEGMENT:
653 /* Logical segment, determin the logical type */
655 switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
657 case CI_LOGICAL_SEG_CLASS_ID:
659 /* Logical Class ID, do a format check */
661 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
663 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
666 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Class Segment (0x%02X)", segment_type );
667 PROTO_ITEM_SET_GENERATED(cia_item);
670 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Class Segment (0x%02X)", segment_type );
672 /* Create a sub tree for the class */
673 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
675 /* Display the 8-bit class number */
678 it = proto_tree_add_uint(cia_tree, hf_cip_class8, NULL, 0, 0, temp_data );
679 PROTO_ITEM_SET_GENERATED(it);
682 proto_tree_add_item( cia_tree, hf_cip_class8, tvb, offset + pathpos + 1, 1, TRUE );
683 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%02X" ) );
685 /* 2 bytes of path used */
688 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
690 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
693 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Class Segment (0x%02X)", segment_type );
694 PROTO_ITEM_SET_GENERATED(cia_item);
697 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Class Segment (0x%02X)", segment_type );
699 /* Create a sub tree for the class */
700 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
702 /* Display the 16-bit class number */
705 it = proto_tree_add_uint(cia_tree, hf_cip_class16, NULL, 0, 0, temp_data );
706 PROTO_ITEM_SET_GENERATED(it);
709 proto_tree_add_item( cia_tree, hf_cip_class16, tvb, offset + pathpos + 2, 2, TRUE );
710 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%04X" ) );
712 /* 4 bytes of path used */
715 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
717 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
720 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
721 PROTO_ITEM_SET_GENERATED(cia_item);
724 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
726 /* Create a sub tree for the class */
727 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
729 /* Display the 32-bit class number */
732 it = proto_tree_add_uint(cia_tree, hf_cip_class32, NULL, 0, 0, temp_data );
733 PROTO_ITEM_SET_GENERATED(it);
736 proto_tree_add_item( cia_tree, hf_cip_class32, tvb, offset + pathpos + 2, 4, TRUE );
737 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%08X" ) );
739 /* 6 bytes of path used */
744 /* Unsupported logical segment format */
745 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
751 case CI_LOGICAL_SEG_INST_ID:
753 /* Logical Instance ID, do a format check */
755 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
757 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
760 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
761 PROTO_ITEM_SET_GENERATED(cia_item);
764 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
766 /* Create a sub tree for the instance */
767 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
769 /* Display the 8-bit instance number */
772 it = proto_tree_add_uint(cia_tree, hf_cip_instance8, NULL, 0, 0, temp_data );
773 PROTO_ITEM_SET_GENERATED(it);
776 proto_tree_add_item( cia_tree, hf_cip_instance8, tvb, offset + pathpos + 1, 1, TRUE );
777 proto_item_append_text( epath_item, "Instance: 0x%02X", temp_data );
779 /* 2 bytes of path used */
782 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
784 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
787 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
788 PROTO_ITEM_SET_GENERATED(cia_item);
791 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
793 /* Create a sub tree for the instance */
794 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
796 /* Display the 16-bit instance number */
799 it = proto_tree_add_uint(cia_tree, hf_cip_instance16, NULL, 0, 0, temp_data );
800 PROTO_ITEM_SET_GENERATED(it);
803 proto_tree_add_item( cia_tree, hf_cip_instance16, tvb, offset + pathpos + 2, 2, TRUE );
804 proto_item_append_text( epath_item, "Instance: 0x%04X", temp_data );
806 /* 4 bytes of path used */
809 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
811 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
814 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
815 PROTO_ITEM_SET_GENERATED(cia_item);
818 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
820 /* Create a sub tree for the instance */
821 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
823 /* Display the 32-bit instance number */
826 it = proto_tree_add_uint(cia_tree, hf_cip_instance32, NULL, 0, 0, temp_data );
827 PROTO_ITEM_SET_GENERATED(it);
830 proto_tree_add_item( cia_tree, hf_cip_instance32, tvb, offset + pathpos + 2, 4, TRUE );
831 proto_item_append_text( epath_item, "Instance: 0x%08X", temp_data );
834 /* 6 bytes of path used */
839 /* Unsupported logical segment format */
840 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
846 case CI_LOGICAL_SEG_MBR_ID:
848 /* Logical Member ID, do a format check */
850 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
852 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
855 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Member Segment (0x%02X)", segment_type );
856 PROTO_ITEM_SET_GENERATED(cia_item);
859 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Member Segment (0x%02X)", segment_type );
861 /* Create a sub tree for the attribute */
862 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
864 /* Display the 8-bit attribute number */
867 it = proto_tree_add_item( cia_tree, hf_cip_member8, NULL, 0, 0, TRUE );
868 PROTO_ITEM_SET_GENERATED(it);
871 proto_tree_add_item( cia_tree, hf_cip_member8, tvb, offset + pathpos + 1, 1, TRUE );
872 proto_item_append_text( epath_item, "Member: 0x%02X", temp_data );
874 /* 2 bytes of path used */
877 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
879 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
882 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Member Segment (0x%02X)", segment_type );
883 PROTO_ITEM_SET_GENERATED(cia_item);
886 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Member Segment (0x%02X)", segment_type );
888 /* Create a sub tree for the attribute */
889 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
891 /* Display the 16-bit attribute number */
894 it = proto_tree_add_item( cia_tree, hf_cip_member16, NULL, 0, 0, TRUE );
895 PROTO_ITEM_SET_GENERATED(it);
898 proto_tree_add_item( cia_tree, hf_cip_member16, tvb, offset + pathpos + 2, 2, TRUE );
899 proto_item_append_text( epath_item, "Member: 0x%04X", temp_data );
901 /* 4 bytes of path used */
904 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
906 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
909 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Member Segment (0x%02X)", segment_type );
910 PROTO_ITEM_SET_GENERATED(cia_item);
913 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Member Segment (0x%02X)", segment_type );
915 /* Create a sub tree for the attribute */
916 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
918 /* Display the 32-bit attribute number */
921 it = proto_tree_add_item( cia_tree, hf_cip_member32, NULL, 0, 0, TRUE );
922 PROTO_ITEM_SET_GENERATED(it);
925 proto_tree_add_item( cia_tree, hf_cip_member32, tvb, offset + pathpos + 2, 4, TRUE );
926 proto_item_append_text( epath_item, "Member: 0x%08X", temp_data );
928 /* 6 bytes of path used */
933 /* Unsupported logical segment format */
934 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
939 case CI_LOGICAL_SEG_ATTR_ID:
941 /* Logical Attribute ID, do a format check */
943 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
945 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
948 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
949 PROTO_ITEM_SET_GENERATED(cia_item);
952 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
954 /* Create a sub tree for the attribute */
955 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
957 /* Display the 8-bit attribute number */
960 it = proto_tree_add_item( cia_tree, hf_cip_attribute8, NULL, 0, 0, TRUE );
961 PROTO_ITEM_SET_GENERATED(it);
964 proto_tree_add_item( cia_tree, hf_cip_attribute8, tvb, offset + pathpos + 1, 1, TRUE );
965 proto_item_append_text( epath_item, "Attribute: 0x%02X", temp_data );
967 /* 2 bytes of path used */
970 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
972 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
975 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
976 PROTO_ITEM_SET_GENERATED(cia_item);
979 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
981 /* Create a sub tree for the attribute */
982 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
984 /* Display the 16-bit attribute number */
987 it = proto_tree_add_item( cia_tree, hf_cip_attribute16, NULL, 0, 0, TRUE );
988 PROTO_ITEM_SET_GENERATED(it);
991 proto_tree_add_item( cia_tree, hf_cip_attribute16, tvb, offset + pathpos + 2, 2, TRUE );
992 proto_item_append_text( epath_item, "Attribute: 0x%04X", temp_data );
994 /* 4 bytes of path used */
997 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
999 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
1002 cia_item = proto_tree_add_text( path_tree, NULL, 0, 0, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
1003 PROTO_ITEM_SET_GENERATED(cia_item);
1006 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
1008 /* Create a sub tree for the attribute */
1009 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
1011 /* Display the 32-bit attribute number */
1014 it = proto_tree_add_item( cia_tree, hf_cip_attribute32, NULL, 0, 0, TRUE );
1015 PROTO_ITEM_SET_GENERATED(it);
1018 proto_tree_add_item( cia_tree, hf_cip_attribute32, tvb, offset + pathpos + 2, 4, TRUE );
1019 proto_item_append_text( epath_item, "Attribute: 0x%08X", temp_data );
1021 /* 6 bytes of path used */
1026 /* Unsupported logical segment format */
1027 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
1033 case CI_LOGICAL_SEG_CON_POINT:
1035 /* Logical Connection point , do a format check */
1037 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
1039 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
1040 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Connection Point Segment (0x%02X)", segment_type );
1042 /* Create a sub tree for the connection point */
1043 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
1045 /* Display the 8-bit connection point number */
1046 proto_tree_add_item( cia_tree, hf_cip_conpoint8, tvb, offset + pathpos + 1, 1, TRUE );
1047 proto_item_append_text( epath_item, "Connection Point: 0x%02X", temp_data );
1049 /* 2 bytes of path used */
1052 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
1054 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
1055 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Connection Point Segment (0x%02X)", segment_type );
1057 /* Create a sub tree for the connection point */
1058 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
1060 /* Display the 16-bit connection point number */
1061 proto_tree_add_item( cia_tree, hf_cip_conpoint16, tvb, offset + pathpos + 2, 2, TRUE );
1062 proto_item_append_text( epath_item, "Connection Point: 0x%04X", temp_data );
1064 /* 4 bytes of path used */
1067 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
1069 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
1070 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Connection Point Segment (0x%02X)", segment_type );
1072 /* Create a sub tree for the connection point */
1073 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
1075 /* Display the 32-bit connection point number */
1076 proto_tree_add_item( cia_tree, hf_cip_conpoint32, tvb, offset + pathpos + 2, 4, TRUE );
1077 proto_item_append_text( epath_item, "Connection Point: 0x%08X", temp_data );
1079 /* 6 bytes of path used */
1084 /* Unsupported logical segment format */
1085 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
1091 case CI_LOGICAL_SEG_SPECIAL:
1093 /* Logical Special ID, the only logical format sepcifyed is electronic key */
1095 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
1097 /* Get the Key Format */
1098 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
1100 if( temp_data == CI_E_KEY_FORMAT_VAL )
1102 qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
1104 /* Create a sub tree for the IOI */
1105 e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
1107 /* Print the key type */
1108 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
1110 /* Get the Vendor ID */
1111 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
1112 proto_tree_add_item( e_key_tree, hf_cip_vendor, tvb, offset + pathpos + 2, 2, TRUE);
1113 proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
1115 /* Get Device Type */
1116 temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
1117 proto_tree_add_item( e_key_tree, hf_cip_devtype, tvb, offset + pathpos + 4, 2, TRUE);
1118 proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
1121 temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
1122 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
1124 /* Major revision/Compatibility */
1125 temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
1127 /* Add Major revision/Compatibility tree */
1128 mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
1129 mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
1131 /* Add Compatibility bit info */
1132 proto_tree_add_item(mc_tree, hf_cip_fwo_comp,
1133 tvb, offset + pathpos + 8, 1, TRUE );
1135 proto_item_append_text( mcpi, "%s, Major Revision: %d",
1136 val_to_str( ( temp_data & 0x80 )>>7, cip_com_bit_vals , "" ),
1139 /* Major revision */
1140 proto_tree_add_item(mc_tree, hf_cip_fwo_mrev,
1141 tvb, offset + pathpos + 8, 1, TRUE );
1143 /* Minor revision */
1144 temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
1145 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
1147 proto_item_append_text( qi, ", %d.%d", ( temp_data & 0x7F ), temp_data2 );
1149 proto_item_append_text(epath_item, "[Key]" );
1151 /* Increment the path pointer */
1156 /* Unsupported electronic key format */
1157 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
1163 /* Unsupported special segment format */
1164 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
1171 /* Unsupported logical segment type */
1172 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
1175 } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
1179 case CI_DATA_SEGMENT:
1181 /* Data segment, determin the logical type */
1183 switch( segment_type )
1185 case CI_DATA_SEG_SIMPLE:
1187 /* Simple data segment */
1190 ds_item = proto_tree_add_text( path_tree, NULL, 0, 0, "Simple Data Segment (0x%02X)", segment_type );
1191 PROTO_ITEM_SET_GENERATED(ds_item);
1194 ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
1196 /* Create a sub tree */
1197 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
1200 seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
1201 proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
1206 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
1208 for( i=0; i < seg_size/2; i ++ )
1210 temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
1211 proto_item_append_text(qi, " 0x%04X", temp_word );
1214 proto_item_set_len(qi, seg_size);
1217 proto_item_set_len( ds_item, 2 + seg_size );
1218 pathpos = pathpos + 2 + seg_size;
1220 proto_item_append_text(epath_item, "[Data]" );
1224 case CI_DATA_SEG_SYMBOL:
1226 /* ANSI extended symbol segment */
1229 ds_item = proto_tree_add_text( path_tree, NULL, 0, 0, "Extended Symbol Segment (0x%02X)", segment_type );
1230 PROTO_ITEM_SET_GENERATED(ds_item);
1233 ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
1235 /* Create a sub tree */
1236 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
1239 seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
1242 it = proto_tree_add_text( ds_tree, NULL, 0, 0, "Data Size: %d", seg_size );
1243 PROTO_ITEM_SET_GENERATED(it);
1246 proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
1253 qi = proto_tree_add_text( ds_tree, NULL, 0, 0, "Data: %s",
1254 tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
1255 PROTO_ITEM_SET_GENERATED(qi);
1258 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2, seg_size, "Data: %s",
1259 tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
1261 proto_item_append_text(epath_item, "%s", tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
1263 hidden_item = proto_tree_add_item( ds_tree, hf_cip_symbol, tvb, offset + pathpos + 2, seg_size, FALSE );
1264 PROTO_ITEM_SET_HIDDEN(hidden_item);
1268 /* We have a PAD BYTE */
1270 proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2 + seg_size, 1, "Pad Byte (0x%02X)",
1271 tvb_get_guint8( tvb, offset + pathpos + 2 + seg_size ) );
1277 proto_item_set_len( ds_item, 2 + seg_size );
1278 pathpos = pathpos + 2 + seg_size;
1283 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
1286 } /* End of switch sub-type */
1290 case CI_NETWORK_SEGMENT:
1292 /* Network segment -Determine the segment sub-type */
1294 switch( segment_type & CI_NETWORK_SEG_TYPE_MASK )
1296 case CI_NETWORK_SEG_SCHEDULE:
1297 net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Schedule" );
1298 net_tree = proto_item_add_subtree( net_item, ett_port_path );
1300 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Multiplier/Phase: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
1302 /* 2 bytes of path used */
1306 case CI_NETWORK_SEG_FIXED_TAG:
1307 net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Fixed Tag" );
1308 net_tree = proto_item_add_subtree( net_item, ett_port_path );
1310 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Fixed Tag: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
1312 /* 2 bytes of path used */
1316 case CI_NETWORK_SEG_PROD_INHI:
1317 net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Production Inhibit" );
1318 net_tree = proto_item_add_subtree( net_item, ett_port_path );
1320 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Production Inhibit Time: %dms", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
1322 /* 2 bytes of path used */
1327 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
1330 } /* End of switch sub-type */
1336 /* Unsupported segment type */
1337 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
1340 } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
1342 /* Next path segment */
1343 if( pathpos < path_length )
1344 proto_item_append_text( epath_item, ", " );
1346 } /* end of while( pathpos < path_length ) */
1348 } /* end of dissect_epath() */
1350 /************************************************
1352 * Dissector for generic CIP object
1354 ************************************************/
1357 dissect_cip_generic_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo, proto_item *ti )
1359 proto_item *pi, *temp_item;
1360 proto_tree *cmd_data_tree;
1362 unsigned char add_stat_size;
1366 if( tvb_get_guint8( tvb, offset ) & 0x80 )
1368 /* Response message */
1369 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
1371 /* If there is any command specific data create a sub-tree for it */
1372 if( ( item_length-4-add_stat_size ) != 0 )
1374 pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
1375 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1378 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1382 PROTO_ITEM_SET_HIDDEN( ti );
1385 } /* End of if reply */
1388 /* Request message */
1390 /* Add service to info column */
1391 if(check_col(pinfo->cinfo, COL_INFO))
1393 col_append_str( pinfo->cinfo, COL_INFO,
1394 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1395 cip_sc_vals , "Unknown Service (0x%02x)") );
1398 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
1400 /* If there is any command specific data creat a sub-tree for it */
1401 if( (item_length-req_path_size-2) != 0 )
1404 pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
1405 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1407 /* Check what service code that recived */
1409 if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
1411 /* Get attribute list request */
1415 /* Add number of services */
1416 att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
1417 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
1419 /* Add Attribute List */
1420 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
1422 for( i=0; i < att_count; i++ )
1424 if( i == (att_count-1) )
1425 proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1427 proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1430 } /* End of Get attribute list request */
1434 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
1435 } /* End of check service code */
1440 PROTO_ITEM_SET_HIDDEN( ti );
1441 } /* End of if command-specific data present */
1443 } /* End of if-else( request ) */
1445 } /* End of dissect_cip_generic_data() */
1448 dissect_cip_class_generic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1451 proto_tree *class_tree;
1455 /* Create display subtree for the protocol */
1456 ti = proto_tree_add_item(tree, proto_cip_class_generic, tvb, 0, -1, FALSE);
1457 class_tree = proto_item_add_subtree( ti, ett_cip_class_generic );
1459 dissect_cip_generic_data( class_tree, tvb, 0, tvb_length(tvb), pinfo, ti );
1462 return tvb_length(tvb);
1465 /************************************************
1467 * Dissector for CIP Message Router
1469 ************************************************/
1472 dissect_cip_mr_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
1475 typedef struct mr_mult_req_info {
1478 cip_req_info_t *requests;
1479 } mr_mult_req_info_t;
1481 proto_item *pi, *rrsc_item, *temp_item, *temp_item2;
1482 proto_tree *temp_tree, *rrsc_tree, *cmd_data_tree;
1485 unsigned char gen_status;
1486 unsigned char add_stat_size;
1487 int num_services, serv_offset;
1488 unsigned char service;
1489 mr_mult_req_info_t *mr_mult_req_info;
1490 cip_req_info_t *mr_single_req_info;
1491 cip_req_info_t *cip_req_info;
1493 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP MR");
1495 /* Add Service code & Request/Response tree */
1496 rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
1497 rrsc_tree = proto_item_add_subtree( rrsc_item, ett_mr_rrsc );
1499 /* Add Request/Response */
1500 proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
1502 /* watch for service collisions */
1503 service = tvb_get_guint8( tvb, offset );
1505 proto_item_append_text( rrsc_item, "%s (%s)",
1506 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1507 cip_sc_vals, "Unknown Service (0x%02x)"),
1508 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
1511 /* Add Service code */
1512 proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
1514 if( tvb_get_guint8( tvb, offset ) & 0x80 )
1516 gen_status = tvb_get_guint8( tvb, offset+2 );
1517 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
1519 /* If there is any command specific data create a sub-tree for it */
1520 if( ( item_length-4-add_stat_size ) != 0 )
1522 pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
1523 cmd_data_tree = proto_item_add_subtree( pi, ett_mr_cmd_data );
1525 if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
1527 /* Success responses */
1529 if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
1531 /* Multiple Service Reply (Success)*/
1533 /* Add number of replies */
1534 num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
1535 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
1538 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
1540 cip_req_info = (cip_req_info_t*)p_get_proto_data( pinfo->fd, proto_cip );
1541 mr_mult_req_info = NULL;
1544 mr_mult_req_info = (mr_mult_req_info_t*)cip_req_info->pData;
1546 if ( mr_mult_req_info
1547 && ( mr_mult_req_info->service != SC_MULT_SERV_PACK
1548 || mr_mult_req_info->num_services != num_services
1551 mr_mult_req_info = NULL;
1554 for( i=0; i < num_services; i++ )
1559 serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
1561 if( i == (num_services-1) )
1563 /* Last service to add */
1564 proto_item_append_text(temp_item, "%d", serv_offset );
1565 serv_length = item_length-add_stat_size-serv_offset-4;
1569 proto_item_append_text(temp_item, "%d, ", serv_offset );
1570 serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
1573 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
1574 temp_tree = proto_item_add_subtree( temp_item2, ett_mr_mult_ser );
1577 ** We call our selves again to disect embedded packet
1580 if(check_col(pinfo->cinfo, COL_INFO))
1581 col_append_str( pinfo->cinfo, COL_INFO, ", ");
1583 next_tvb = tvb_new_subset(tvb, offset+serv_offset+4, serv_length, serv_length);
1584 if ( mr_mult_req_info )
1586 mr_single_req_info = mr_mult_req_info->requests + i;
1587 dissect_cip_data( temp_tree, next_tvb, 0, pinfo, mr_single_req_info );
1591 dissect_cip_data( temp_tree, next_tvb, 0, pinfo, NULL );
1594 } /* End if Multiple service Packet */
1595 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
1597 /* Get Attribute List Reply (Success)*/
1601 /* Add Attribute Count */
1602 att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
1603 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
1606 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
1608 } /* End if GetAttrList */
1612 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1613 } /* end of check service code */
1618 /* Error responses */
1621 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1623 } /* end of if-else( CI_CRC_SUCCESS ) */
1625 } /* End of if command-specific data present */
1627 } /* End of if reply */
1630 /* Request message */
1632 /* Add service to info column */
1633 if(check_col(pinfo->cinfo, COL_INFO))
1635 col_append_str( pinfo->cinfo, COL_INFO,
1636 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1637 cip_sc_vals, "Unknown Service (0x%02x)") );
1640 /* Add path size to tree */
1641 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
1643 /* If there is any command specific data creat a sub-tree for it */
1644 if( (item_length-req_path_size-2) != 0 )
1647 pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
1648 cmd_data_tree = proto_item_add_subtree( pi, ett_mr_cmd_data );
1650 /* Check what service code that recived */
1652 if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
1654 /* Multiple service packet */
1656 /* Add number of services */
1657 num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
1658 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
1661 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
1663 cip_req_info = (cip_req_info_t*)p_get_proto_data( pinfo->fd, proto_cip );
1665 mr_mult_req_info = NULL;
1668 if ( cip_req_info->pData == NULL )
1670 mr_mult_req_info = se_alloc(sizeof(mr_mult_req_info_t));
1671 mr_mult_req_info->service = SC_MULT_SERV_PACK;
1672 mr_mult_req_info->num_services = num_services;
1673 mr_mult_req_info->requests = se_alloc(sizeof(cip_req_info_t)*num_services);
1674 cip_req_info->pData = mr_mult_req_info;
1678 mr_mult_req_info = (mr_mult_req_info_t*)cip_req_info->pData;
1679 if ( mr_mult_req_info && mr_mult_req_info->num_services != num_services )
1680 mr_mult_req_info = NULL;
1683 for( i=0; i < num_services; i++ )
1688 serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
1690 if( i == (num_services-1) )
1692 /* Last service to add */
1693 serv_length = item_length-2-req_path_size-serv_offset;
1694 proto_item_append_text(temp_item, "%d", serv_offset );
1698 serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
1699 proto_item_append_text(temp_item, "%d, ", serv_offset );
1702 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
1703 temp_tree = proto_item_add_subtree( temp_item2, ett_mr_mult_ser );
1706 ** We call our selves again to disect embedded packet
1709 if(check_col(pinfo->cinfo, COL_INFO))
1710 col_append_str( pinfo->cinfo, COL_INFO, ", ");
1712 next_tvb = tvb_new_subset(tvb, offset+serv_offset+6, serv_length, serv_length);
1714 if ( mr_mult_req_info )
1716 mr_single_req_info = mr_mult_req_info->requests + i;
1717 mr_single_req_info->bService = 0;
1718 mr_single_req_info->dissector = NULL;
1719 mr_single_req_info->IOILen = 0;
1720 mr_single_req_info->pIOI = NULL;
1721 mr_single_req_info->pData = NULL;
1723 dissect_cip_data( temp_tree, next_tvb, 0, pinfo, mr_single_req_info );
1727 dissect_cip_data( temp_tree, next_tvb, 0, pinfo, NULL );
1730 } /* End if Multiple service Packet */
1731 else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
1733 /* Get attribute list request */
1737 /* Add number of services */
1738 att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
1739 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
1741 /* Add Attribute List */
1742 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
1744 for( i=0; i < att_count; i++ )
1746 if( i == (att_count-1) )
1747 proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1749 proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1752 } /* End of Get attribute list request */
1756 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
1757 } /* End of check service code */
1759 } /* End of if command-specific data present */
1761 } /* End of if-else( request ) */
1763 } /* End of dissect_cip_mr() */
1766 dissect_cip_class_mr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1769 proto_tree *class_tree;
1773 /* Create display subtree for the protocol */
1774 ti = proto_tree_add_item(tree, proto_cip_class_mr, tvb, 0, -1, FALSE);
1775 class_tree = proto_item_add_subtree( ti, ett_cip_class_mr );
1777 dissect_cip_mr_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
1780 return tvb_length(tvb);
1783 /************************************************
1785 * Dissector for CIP Connection Manager
1787 ************************************************/
1790 dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
1792 proto_item *pi, *rrsc_item, *ncppi, *ar_item, *temp_item;
1793 proto_tree *temp_tree, *rrsc_tree, *ncp_tree, *cmd_data_tree;
1794 int req_path_size, conn_path_size, temp_data;
1795 unsigned char gen_status;
1796 unsigned char add_stat_size;
1797 unsigned short add_status;
1798 unsigned char temp_byte, route_path_size;
1799 unsigned char app_rep_size, i;
1801 unsigned char service;
1802 cip_req_info_t *preq_info;
1803 cip_req_info_t *pembedded_req_info;
1805 /* Special handling for Unconnected send response. If successful, embedded service code is sent.
1806 * If failed, it can be either an Unconnected send response or the embedded service code response. */
1807 preq_info = (cip_req_info_t*)p_get_proto_data( pinfo->fd, proto_cip );
1808 if ( preq_info && ( tvb_get_guint8( tvb, offset ) & 0x80 )
1809 && preq_info->bService == SC_CM_UNCON_SEND
1812 gen_status = tvb_get_guint8( tvb, offset+2 );
1813 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
1814 if ( add_stat_size == 2 )
1815 add_status = tvb_get_letohs( tvb, offset + 4 );
1818 if( gen_status == 0 /* success response ) */
1819 || ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) != SC_CM_UNCON_SEND )
1820 || !( ( gen_status == 0x01 && ( add_status == 0x0204 || add_status == 0x0311 || add_status == 0x0312 || add_status == 0x0315 ) )
1821 || gen_status == 0x02
1822 || gen_status == 0x04
1826 pembedded_req_info = (cip_req_info_t*)preq_info->pData;
1828 if ( pembedded_req_info )
1831 void *p_save_proto_data;
1833 p_save_proto_data = p_get_proto_data( pinfo->fd, proto_cip );
1834 p_remove_proto_data(pinfo->fd, proto_cip);
1835 p_add_proto_data(pinfo->fd, proto_cip, pembedded_req_info );
1837 rrsc_item = proto_tree_add_text( item_tree, NULL, 0, 0, "(Service: Unconnected Send (Response))" );
1838 next_tvb = tvb_new_subset(tvb, offset, item_length, item_length);
1839 if ( pembedded_req_info && pembedded_req_info->dissector )
1840 call_dissector(pembedded_req_info->dissector, next_tvb, pinfo, item_tree );
1842 call_dissector( cip_class_generic_handle, next_tvb, pinfo, item_tree );
1844 p_remove_proto_data(pinfo->fd, proto_cip);
1845 p_add_proto_data(pinfo->fd, proto_cip, p_save_proto_data);
1851 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP CM");
1853 /* Add Service code & Request/Response tree */
1854 rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
1855 rrsc_tree = proto_item_add_subtree( rrsc_item, ett_cm_rrsc );
1857 /* Add Request/Response */
1858 proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
1860 /* watch for service collisions */
1861 service = tvb_get_guint8( tvb, offset );
1862 proto_item_append_text( rrsc_item, "%s (%s)",
1863 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1864 cip_sc_vals_cm , "Unknown Service (0x%02x)"),
1865 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
1868 /* Add Service code */
1869 proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
1871 if( tvb_get_guint8( tvb, offset ) & 0x80 )
1873 /* Response message */
1874 gen_status = tvb_get_guint8( tvb, offset+2 );
1875 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
1877 /* If there is any command specific data create a sub-tree for it */
1878 if( ( item_length-4-add_stat_size ) != 0 )
1880 pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
1881 cmd_data_tree = proto_item_add_subtree( pi, ett_cm_cmd_data );
1883 if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
1885 /* Success responses */
1887 if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_OPEN )
1889 /* Forward open Response (Success) */
1892 guint16 ConnSerialNumber;
1893 guint32 DeviceSerialNumber;
1896 /* Display originator to target connection ID */
1897 O2TConnID = tvb_get_letohl( tvb, offset+4+add_stat_size );
1898 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", O2TConnID );
1900 /* Display target to originator connection ID */
1901 T2OConnID = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1902 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", T2OConnID );
1904 /* Display connection serial number */
1905 ConnSerialNumber = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
1906 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", ConnSerialNumber );
1908 /* Display the originator vendor id */
1909 VendorID = tvb_get_letohs( tvb, offset+4+add_stat_size+10 );
1910 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+10, 2, TRUE);
1912 /* Display the originator serial number */
1913 DeviceSerialNumber = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
1914 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", DeviceSerialNumber );
1916 /* Display originator to target actual packet interval */
1917 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
1918 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 );
1920 /* Display originator to target actual packet interval */
1921 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
1922 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 );
1924 /* Display the application reply size */
1925 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
1926 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1928 /* Display the Reserved byte */
1929 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
1930 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
1932 if( app_rep_size != 0 )
1934 /* Display application Reply data */
1935 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
1937 for( i=0; i < app_rep_size; i++ )
1939 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
1940 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1943 } /* End of if reply data */
1945 enip_open_cip_connection( pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber, O2TConnID, T2OConnID );
1947 } /* End of if forward open response */
1948 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_CLOSE )
1950 /* Forward close response (Success) */
1951 guint16 ConnSerialNumber;
1952 guint32 DeviceSerialNumber;
1955 /* Display connection serial number */
1956 ConnSerialNumber = tvb_get_letohs( tvb, offset+4+add_stat_size );
1957 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", ConnSerialNumber );
1959 /* Display the originator vendor id */
1960 VendorID = tvb_get_letohs( tvb, offset+4+add_stat_size+2 );
1961 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
1963 /* Display the originator serial number */
1964 DeviceSerialNumber = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1965 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", DeviceSerialNumber );
1967 /* Display the application reply size */
1968 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
1969 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1971 /* Display the Reserved byte */
1972 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1973 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
1975 if( app_rep_size != 0 )
1977 /* Display application Reply data */
1978 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
1980 for( i=0; i < app_rep_size; i ++ )
1982 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
1983 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1986 } /* End of if reply data */
1988 enip_close_cip_connection( pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber );
1990 } /* End of if forward close response */
1991 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_UNCON_SEND )
1993 /* Unconnected send response (Success) */
1995 /* Display service response data */
1996 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1998 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
2000 /* Get Attribute List Reply (Success)*/
2004 /* Add Attribute Count */
2005 att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
2006 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
2009 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
2011 } /* Get Attribute List Reply */
2015 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
2016 } /* end of check service code */
2021 /* Error responses */
2023 if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_OPEN ) ||
2024 ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_FWD_CLOSE ) )
2026 /* Forward open and forward close error response look the same */
2028 /* Display connection serial number */
2029 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
2030 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
2032 /* Display the originator vendor id */
2033 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
2035 /* Display the originator serial number */
2036 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
2037 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
2039 /* Display remaining path size */
2040 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
2041 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
2043 /* Display reserved data */
2044 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
2045 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
2047 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_CM_UNCON_SEND )
2049 /* Unconnected send response (Unsuccess) */
2051 /* Display remaining path size */
2052 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
2053 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
2058 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
2061 } /* end of if-else( CI_CRC_SUCCESS ) */
2063 } /* End of if command-specific data present */
2065 } /* End of if reply */
2068 /* Request message */
2070 /* Add service to info column */
2071 if(check_col(pinfo->cinfo, COL_INFO))
2073 col_append_str( pinfo->cinfo, COL_INFO,
2074 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
2075 cip_sc_vals_cm , "Unknown Service (0x%02x)") );
2077 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
2079 /* If there is any command specific data creat a sub-tree for it */
2080 if( (item_length-req_path_size-2) != 0 )
2083 pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
2084 cmd_data_tree = proto_item_add_subtree( pi, ett_cm_cmd_data );
2086 /* Check what service code that recived */
2088 if( tvb_get_guint8( tvb, offset ) == SC_CM_FWD_OPEN )
2090 /* Forward open Request*/
2092 /* Display the priority/tick timer */
2093 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
2094 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
2096 /* Display the time-out ticks */
2097 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
2098 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
2100 /* Display the actual time out */
2101 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
2102 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
2104 /* Display originator to taget connection ID */
2105 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
2106 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
2108 /* Display target to originator connection ID */
2109 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
2110 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
2112 /* Display connection serial number */
2113 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
2114 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
2116 /* Display the originator vendor id */
2117 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+12, 2, TRUE);
2119 /* Display the originator serial number */
2120 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
2121 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
2123 /* Display the timeout multiplier */
2124 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
2125 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 );
2127 /* Put out an indicator for the reserved bytes */
2128 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
2130 /* Display originator to target requested packet interval */
2131 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
2132 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 );
2134 /* Display originator to target network connection patameterts, in a tree */
2135 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
2136 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 );
2137 ncp_tree = proto_item_add_subtree(ncppi, ett_cm_ncp);
2139 /* Add the data to the tree */
2140 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_own,
2141 tvb, offset+2+req_path_size+26, 2, TRUE );
2142 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_typ,
2143 tvb, offset+2+req_path_size+26, 2, TRUE );
2144 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_prio,
2145 tvb, offset+2+req_path_size+26, 2, TRUE );
2146 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_fixed_var,
2147 tvb, offset+2+req_path_size+26, 2, TRUE );
2148 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_con_size,
2149 tvb, offset+2+req_path_size+26, 2, TRUE );
2151 /* Display target to originator requested packet interval */
2152 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
2153 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 );
2155 /* Display target to originator network connection patameterts, in a tree */
2156 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
2157 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 );
2158 ncp_tree = proto_item_add_subtree(ncppi, ett_cm_ncp);
2160 /* Add the data to the tree */
2161 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_own,
2162 tvb, offset+2+req_path_size+32, 2, TRUE );
2163 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_typ,
2164 tvb, offset+2+req_path_size+32, 2, TRUE );
2165 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_prio,
2166 tvb, offset+2+req_path_size+32, 2, TRUE );
2167 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_fixed_var,
2168 tvb, offset+2+req_path_size+32, 2, TRUE );
2169 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_con_size,
2170 tvb, offset+2+req_path_size+32, 2, TRUE );
2172 /* Transport type/trigger in tree*/
2173 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
2175 ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
2176 ncp_tree = proto_item_add_subtree(ncppi, ett_cm_ncp);
2178 /* Add the data to the tree */
2179 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_dir,
2180 tvb, offset+2+req_path_size+34, 1, TRUE );
2182 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_trigg,
2183 tvb, offset+2+req_path_size+34, 1, TRUE );
2185 proto_tree_add_item(ncp_tree, hf_cip_cm_fwo_class,
2186 tvb, offset+2+req_path_size+34, 1, TRUE );
2189 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
2190 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
2193 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
2194 dissect_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size, FALSE );
2196 else if( tvb_get_guint8( tvb, offset ) == SC_CM_FWD_CLOSE )
2198 /* Forward Close Request */
2200 /* Display the priority/tick timer */
2201 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
2202 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
2204 /* Display the time-out ticks */
2205 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
2206 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
2208 /* Display the actual time out */
2209 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
2210 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
2212 /* Display connection serial number */
2213 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
2214 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
2216 /* Display the originator vendor id */
2217 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+4, 2, TRUE);
2219 /* Display the originator serial number */
2220 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
2221 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
2223 /* Add the path size */
2224 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
2225 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
2227 /* Add the reserved byte */
2228 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
2229 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
2232 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
2233 dissect_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size, FALSE );
2235 } /* End of forward close */
2236 else if( tvb_get_guint8( tvb, offset ) == SC_CM_UNCON_SEND )
2238 /* Unconnected send */
2241 /* Display the priority/tick timer */
2242 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
2243 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
2245 /* Display the time-out ticks */
2246 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
2247 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
2249 /* Display the actual time out */
2250 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
2251 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
2253 /* Message request size */
2254 msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
2255 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
2257 /* Message Request */
2258 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
2259 temp_tree = proto_item_add_subtree(temp_item, ett_cm_mes_req );
2262 ** We call our selves again to disect embedded packet
2265 if(check_col(pinfo->cinfo, COL_INFO))
2266 col_append_str( pinfo->cinfo, COL_INFO, ": ");
2268 next_tvb = tvb_new_subset(tvb, offset+2+req_path_size+4, msg_req_siz, msg_req_siz);
2269 preq_info = p_get_proto_data( pinfo->fd, proto_cip );
2270 pembedded_req_info = NULL;
2273 if ( preq_info->pData == NULL )
2275 pembedded_req_info = (cip_req_info_t*)se_alloc(sizeof(cip_req_info_t));
2276 pembedded_req_info->bService = 0;
2277 pembedded_req_info->dissector = NULL;
2278 pembedded_req_info->IOILen = 0;
2279 pembedded_req_info->pIOI = NULL;
2280 pembedded_req_info->pData = NULL;
2281 preq_info->pData = pembedded_req_info;
2285 pembedded_req_info = (cip_req_info_t*)preq_info->pData;
2288 dissect_cip_data( temp_tree, next_tvb, 0, pinfo, pembedded_req_info );
2290 if( msg_req_siz % 2 )
2293 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
2294 tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
2295 msg_req_siz++; /* include the padding */
2298 /* Route Path Size */
2299 route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
2300 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 );
2303 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
2304 tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
2307 temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path: ");
2308 dissect_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size, FALSE );
2309 } /* End if unconnected send */
2310 else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
2312 /* Get attribute list request */
2316 /* Add number of services */
2317 att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
2318 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
2320 /* Add Attribute List */
2321 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
2323 for( i=0; i < att_count; i++ )
2325 if( i == (att_count-1) )
2326 proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
2328 proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
2331 } /* End of Get attribute list request */
2335 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
2336 } /* End of check service code */
2338 } /* End of if command-specific data present */
2340 } /* End of if-else( request ) */
2342 } /* End of dissect_cip_cm_data() */
2345 dissect_cip_class_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2348 proto_tree *class_tree;
2352 /* Create display subtree for the protocol */
2353 ti = proto_tree_add_item(tree, proto_cip_class_cm, tvb, 0, -1, FALSE);
2354 class_tree = proto_item_add_subtree( ti, ett_cip_class_cm );
2356 dissect_cip_cm_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
2359 return tvb_length(tvb);
2362 /************************************************
2364 * Dissector for CIP Connection Configuration Object
2366 ************************************************/
2369 dissect_cip_cco_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
2371 proto_item *pi, *rrsc_item, *temp_item;
2372 proto_tree *rrsc_tree, *cmd_data_tree;
2373 int req_path_size, temp_data;
2374 unsigned char gen_status;
2375 unsigned char add_stat_size;
2378 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP CCO");
2380 /* Add Service code & Request/Response tree */
2381 rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
2382 rrsc_tree = proto_item_add_subtree( rrsc_item, ett_cco_rrsc );
2384 /* Add Request/Response */
2385 proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
2387 proto_item_append_text( rrsc_item, "%s (%s)",
2388 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
2389 cip_sc_vals_cco , "Unknown Service (0x%02x)"),
2390 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
2393 /* Add Service code */
2394 proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
2396 if( tvb_get_guint8( tvb, offset ) & 0x80 )
2398 /* Response message */
2400 /* Add additional status size */
2401 gen_status = tvb_get_guint8( tvb, offset+2 );
2402 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
2404 /* If there is any command specific data create a sub-tree for it */
2405 if( ( item_length-4-add_stat_size ) != 0 )
2407 pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
2408 cmd_data_tree = proto_item_add_subtree( pi, ett_cco_cmd_data );
2410 if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
2412 /* Success responses */
2415 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
2419 /* Error responses */
2422 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
2423 } /* end of if-else( CI_CRC_SUCCESS ) */
2425 } /* End of if command-specific data present */
2427 } /* End of if reply */
2430 /* Request message */
2432 /* Add service to info column */
2433 if(check_col(pinfo->cinfo, COL_INFO))
2435 col_append_str( pinfo->cinfo, COL_INFO,
2436 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
2437 cip_sc_vals_cco , "Unknown Service (0x%02x)") );
2439 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
2441 /* If there is any command specific data creat a sub-tree for it */
2442 if( (item_length-req_path_size-2) != 0 )
2445 pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
2446 cmd_data_tree = proto_item_add_subtree( pi, ett_cco_cmd_data );
2448 /* Check what service code that recived */
2450 if( tvb_get_guint8( tvb, offset ) == SC_CCO_AUDIT_CHANGE )
2454 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size );
2455 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Change Type: ");
2458 proto_item_append_text(temp_item, "Full" );
2459 else if (temp_data == 1)
2460 proto_item_append_text(temp_item, "Incremental" );
2462 proto_item_append_text(temp_item, "Reserved" );
2464 else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
2466 /* Get attribute list request */
2470 /* Add number of services */
2471 att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
2472 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
2474 /* Add Attribute List */
2475 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
2477 for( i=0; i < att_count; i++ )
2479 if( i == (att_count-1) )
2480 proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
2482 proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
2485 } /* End of Get attribute list request */
2486 else if ( tvb_get_guint8( tvb, offset ) == SC_CCO_CHANGE_COMPLETE )
2488 /* Change complete request */
2490 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size );
2491 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Change Type: ");
2494 proto_item_append_text(temp_item, "Full" );
2495 else if (temp_data == 1)
2496 proto_item_append_text(temp_item, "Incremental" );
2498 proto_item_append_text(temp_item, "Reserved" );
2503 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
2504 } /* End of check service code */
2506 } /* End of if command-specific data present */
2508 } /* End of if-else( request ) */
2510 } /* End of dissect_cip_cco_data() */
2513 dissect_cip_class_cco(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2516 proto_tree *class_tree;
2520 /* Create display subtree for the protocol */
2521 ti = proto_tree_add_item(tree, proto_cip_class_cco, tvb, 0, -1, FALSE);
2522 class_tree = proto_item_add_subtree( ti, ett_cip_class_cco );
2524 dissect_cip_cco_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
2527 return tvb_length(tvb);
2530 /************************************************
2532 * Dissector for CIP Request/Response
2533 * - matches requests/responses
2534 * - calls class specific dissector
2536 ************************************************/
2539 dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info *pinfo, cip_req_info_t* preq_info )
2542 proto_tree *cip_tree;
2543 proto_item *pi, *rrsc_item, *status_item;
2544 proto_tree *rrsc_tree, *status_tree;
2546 unsigned char gen_status;
2547 unsigned char add_stat_size;
2550 unsigned char service,ioilen,segment;
2551 void *p_save_proto_data;
2552 dissector_handle_t dissector;
2554 p_save_proto_data = p_get_proto_data(pinfo->fd, proto_cip);
2555 p_remove_proto_data(pinfo->fd, proto_cip);
2556 p_add_proto_data(pinfo->fd, proto_cip, preq_info);
2558 /* Create display subtree for the protocol */
2559 ti = proto_tree_add_item(item_tree, proto_cip, tvb, 0, -1, FALSE);
2560 cip_tree = proto_item_add_subtree( ti, ett_cip );
2562 /* Add Service code & Request/Response tree */
2563 rrsc_item = proto_tree_add_text( cip_tree, tvb, offset, 1, "Service: " );
2564 rrsc_tree = proto_item_add_subtree( rrsc_item, ett_rrsc );
2566 /* Add Request/Response */
2567 proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
2569 /* watch for service collisions */
2570 service = tvb_get_guint8( tvb, offset );
2571 proto_item_append_text( rrsc_item, "%s (%s)",
2572 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
2573 cip_sc_vals , "Unknown Service (0x%02x)"),
2574 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
2577 /* Add Service code */
2578 proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
2580 if( service & 0x80 )
2582 /* Response message */
2583 status_item = proto_tree_add_text( cip_tree, tvb, offset+2, 1, "Status: " );
2584 status_tree = proto_item_add_subtree( status_item, ett_status_item );
2586 /* Add general status */
2587 gen_status = tvb_get_guint8( tvb, offset+2 );
2588 proto_tree_add_item(status_tree, hf_cip_genstat, tvb, offset+2, 1, TRUE );
2589 proto_item_append_text( status_item, "%s", val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
2590 cip_gs_vals , "Unknown Response (%x)") );
2592 /* Add reply status to info column */
2593 if(check_col(pinfo->cinfo, COL_INFO))
2595 col_append_str( pinfo->cinfo, COL_INFO,
2596 val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
2597 cip_gs_vals , "Unknown Response (%x)") );
2600 /* Add additional status size */
2601 proto_tree_add_text( status_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)",
2602 tvb_get_guint8( tvb, offset+3 ) );
2604 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
2608 proto_item_append_text( status_item, ", Extended:" );
2610 /* Add additional status */
2611 pi = proto_tree_add_text( status_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
2613 for( i=0; i < add_stat_size/2; i ++ )
2615 proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
2616 proto_item_append_text( status_item, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
2620 proto_item_set_len( status_item, 2 + add_stat_size );
2624 && !( preq_info->bService == ( service & 0x7F )
2625 || ( preq_info->bService == SC_CM_UNCON_SEND && preq_info->dissector == cip_class_cm_handle )
2632 if ( preq_info->IOILen && preq_info->pIOI )
2636 tvbIOI = tvb_new_real_data( preq_info->pIOI, preq_info->IOILen * 2, preq_info->IOILen * 2);
2639 /* pi = add_byte_array_text_to_proto_tree( cip_tree, tvbIOI, 0, req_path_size+1, "IOI: " );
2640 PROTO_ITEM_SET_GENERATED(pi); */
2642 pi = proto_tree_add_text( cip_tree, NULL, 0, 0, "Request Path Size: %d (words)", preq_info->IOILen );
2643 PROTO_ITEM_SET_GENERATED(pi);
2646 pi = proto_tree_add_text(cip_tree, NULL, 0, 0, "Request Path: ");
2647 PROTO_ITEM_SET_GENERATED(pi);
2648 dissect_epath( tvbIOI, pi, 0, preq_info->IOILen, TRUE );
2654 if ( preq_info && preq_info->dissector )
2656 call_dissector( preq_info->dissector, tvb, pinfo, item_tree );
2660 call_dissector( cip_class_generic_handle, tvb, pinfo, item_tree );
2662 } /* End of if reply */
2665 /* Request message */
2667 /* Add path size to tree */
2668 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
2669 proto_tree_add_text( cip_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
2672 pi = proto_tree_add_text(cip_tree, tvb, offset+2, req_path_size, "Request Path: ");
2673 dissect_epath( tvb, pi, offset+2, req_path_size, FALSE );
2675 /* parse IOI; extract class ID */
2676 ioilen = tvb_get_guint8( tvb, offset + 1 );
2678 preq_info->dissector = NULL;
2682 segment = tvb_get_guint8( tvb, offset + 2 );
2683 switch ( segment & CI_SEGMENT_TYPE_MASK )
2685 case CI_LOGICAL_SEGMENT:
2686 /* Logical segment, determin the logical type */
2687 switch( segment & CI_LOGICAL_SEG_TYPE_MASK )
2689 case CI_LOGICAL_SEG_CLASS_ID:
2691 /* Logical Class ID, do a format check */
2693 switch ( segment & CI_LOGICAL_SEG_FORMAT_MASK )
2695 case CI_LOGICAL_SEG_8_BIT:
2696 classid = tvb_get_guint8( tvb, offset + 3 );
2698 case CI_LOGICAL_SEG_16_BIT:
2700 classid = tvb_get_letohs( tvb, offset + 4 );
2702 case CI_LOGICAL_SEG_32_BIT:
2704 classid = tvb_get_letohl( tvb, offset + 4 );
2707 dissector = dissector_get_port_handle( subdissector_class_table, classid );
2709 preq_info->dissector = dissector;
2714 case CI_DATA_SEGMENT:
2715 dissector = dissector_get_port_handle( subdissector_symbol_table, segment );
2717 preq_info->dissector = dissector;
2722 /* copy IOI for access by response packet */
2723 preq_info->pIOI = se_alloc( ioilen*2);
2724 if ( preq_info->pIOI )
2726 preq_info->IOILen = ioilen;
2727 tvb_memcpy(tvb, preq_info->pIOI, offset+2, ioilen*2);
2733 preq_info->bService = service;
2737 call_dissector( dissector, tvb, pinfo, item_tree );
2741 call_dissector( cip_class_generic_handle, tvb, pinfo, item_tree );
2743 } /* End of if-else( request ) */
2745 p_remove_proto_data(pinfo->fd, proto_cip);
2746 p_add_proto_data(pinfo->fd, proto_cip, p_save_proto_data);
2748 } /* End of dissect_cip_data() */
2752 dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2754 enip_request_info_t *enip_info;
2755 cip_req_info_t *preq_info;
2757 /* Make entries in Protocol column and Info column on summary display */
2758 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP");
2760 col_clear(pinfo->cinfo, COL_INFO);
2762 /* Each CIP request received by ENIP gets a unique ID */
2763 enip_info = (enip_request_info_t*)p_get_proto_data(pinfo->fd, proto_enip);
2767 preq_info = (cip_req_info_t*)enip_info->cip_info;
2768 if ( preq_info == NULL )
2770 preq_info = se_alloc( sizeof( cip_req_info_t ) );
2773 preq_info->bService = 0;
2774 preq_info->dissector = NULL;
2775 preq_info->IOILen = 0;
2776 preq_info->pIOI = NULL;
2777 preq_info->pData = NULL;
2778 enip_info->cip_info = preq_info;
2781 dissect_cip_data( tree, tvb, 0, pinfo, enip_info->cip_info );
2785 dissect_cip_data( tree, tvb, 0, pinfo, NULL );
2788 return tvb_length(tvb);
2792 * Protocol initialization
2796 cip_init_protocol(void)
2798 proto_enip = proto_get_id_by_filter_name( "enip" );
2802 proto_register_cip(void)
2804 /* Setup list of header fields */
2805 static hf_register_info hf[] = {
2808 { "Request/Response", "cip.rr",
2809 FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
2810 "Request or Response message", HFILL }
2813 { "Service", "cip.sc",
2814 FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
2815 "Service Code", HFILL }
2818 { "EPath", "cip.epath",
2819 FT_BYTES, BASE_NONE, NULL, 0,
2823 { "General Status", "cip.genstat",
2824 FT_UINT8, BASE_HEX, VALS(cip_gs_vals), 0,
2828 { "Port", "cip.port",
2829 FT_UINT8, BASE_DEC, NULL, 0,
2830 "Port Identifier", HFILL }
2832 { &hf_cip_link_address_byte,
2833 { "Link Address", "cip.linkaddress",
2834 FT_UINT8, BASE_DEC, NULL, 0,
2837 { &hf_cip_link_address_string,
2838 { "Link Address", "cip.linkaddress",
2839 FT_STRING, BASE_NONE, NULL, 0,
2843 { "Class", "cip.class",
2844 FT_UINT8, BASE_HEX, VALS(cip_class_names_vals), 0,
2848 { "Class", "cip.class",
2849 FT_UINT16, BASE_HEX, VALS(cip_class_names_vals), 0,
2853 { "Class", "cip.class",
2854 FT_UINT32, BASE_HEX, VALS(cip_class_names_vals), 0,
2857 { &hf_cip_instance8,
2858 { "Instance", "cip.instance",
2859 FT_UINT8, BASE_HEX, NULL, 0,
2862 { &hf_cip_instance16,
2863 { "Instance", "cip.instance",
2864 FT_UINT16, BASE_HEX, NULL, 0,
2867 { &hf_cip_instance32,
2868 { "Instance", "cip.instance",
2869 FT_UINT32, BASE_HEX, NULL, 0,
2873 { "Member", "cip.member",
2874 FT_UINT8, BASE_HEX, NULL, 0,
2878 { "Member", "cip.member",
2879 FT_UINT16, BASE_HEX, NULL, 0,
2883 { "Member", "cip.member",
2884 FT_UINT32, BASE_HEX, NULL, 0,
2887 { &hf_cip_attribute8,
2888 { "Attribute", "cip.attribute",
2889 FT_UINT8, BASE_HEX, NULL, 0,
2892 { &hf_cip_attribute16,
2893 { "Attribute", "cip.attribute",
2894 FT_UINT16, BASE_HEX, NULL, 0,
2897 { &hf_cip_attribute32,
2898 { "Attribute", "cip.attribute",
2899 FT_UINT32, BASE_HEX, NULL, 0,
2902 { &hf_cip_conpoint8,
2903 { "Connection Point", "cip.connpoint",
2904 FT_UINT8, BASE_HEX, NULL, 0,
2907 { &hf_cip_conpoint16,
2908 { "Connection Point", "cip.connpoint",
2909 FT_UINT16, BASE_HEX, NULL, 0,
2912 { &hf_cip_conpoint32,
2913 { "Connection Point", "cip.connpoint",
2914 FT_UINT16, BASE_HEX, NULL, 0,
2918 { "Symbol", "cip.symbol",
2919 FT_STRING, BASE_NONE, NULL, 0,
2920 "ANSI Extended Symbol Segment", HFILL }
2923 { "Vendor ID", "cip.vendor",
2924 FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
2928 { "Device Type", "cip.devtype",
2929 FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
2933 { "Compatibility", "cip.fwo.cmp",
2934 FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80,
2935 "EKey: Compatibility bit", HFILL }
2938 { "Major Revision", "cip.fwo.major",
2939 FT_UINT8, BASE_DEC, NULL, 0x7F,
2940 "EKey: Major Revision", HFILL }
2944 static hf_register_info hf_cm[] = {
2946 { "Request/Response", "cip.rr",
2947 FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
2948 "Request or Response message", HFILL }
2951 { "Service", "cip.sc",
2952 FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
2953 "Service Code", HFILL }
2955 { &hf_cip_cm_fwo_comp,
2956 { "Compatibility", "cip.cm.fwo.cmp",
2957 FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80,
2958 "Fwd Open: Compatibility bit", HFILL }
2960 { &hf_cip_cm_fwo_mrev,
2961 { "Major Revision", "cip.cm.fwo.major",
2962 FT_UINT8, BASE_DEC, NULL, 0x7F,
2963 "Fwd Open: Major Revision", HFILL }
2965 { &hf_cip_cm_fwo_con_size,
2966 { "Connection Size", "cip.cm.fwo.consize",
2967 FT_UINT16, BASE_DEC, NULL, 0x01FF,
2968 "Fwd Open: Connection size", HFILL }
2970 { &hf_cip_cm_fwo_fixed_var,
2971 { "Connection Size Type", "cip.cm.fwo.f_v",
2972 FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200,
2973 "Fwd Open: Fixed or variable connection size", HFILL }
2975 { &hf_cip_cm_fwo_prio,
2976 { "Priority", "cip.cm.fwo.prio",
2977 FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00,
2978 "Fwd Open: Connection priority", HFILL }
2980 { &hf_cip_cm_fwo_typ,
2981 { "Connection Type", "cip.cm.fwo.type",
2982 FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000,
2983 "Fwd Open: Connection type", HFILL }
2985 { &hf_cip_cm_fwo_own,
2986 { "Owner", "cip.cm.fwo.owner",
2987 FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000,
2988 "Fwd Open: Redundant owner bit", HFILL }
2990 { &hf_cip_cm_fwo_dir,
2991 { "Direction", "cip.cm.fwo.dir",
2992 FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), 0x80,
2993 "Fwd Open: Direction", HFILL }
2995 { &hf_cip_cm_fwo_trigg,
2996 { "Trigger", "cip.cm.fwo.trigger",
2997 FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), 0x70,
2998 "Fwd Open: Production trigger", HFILL }
3000 { &hf_cip_cm_fwo_class,
3001 { "Class", "cip.cm.fwo.transport",
3002 FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), 0x0F,
3003 "Fwd Open: Transport Class", HFILL }
3007 static hf_register_info hf_mr[] = {
3009 { "Request/Response", "cip.rr",
3010 FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
3011 "Request or Response message", HFILL }
3014 { "Service", "cip.sc",
3015 FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
3016 "Service Code", HFILL }
3020 static hf_register_info hf_cco[] = {
3022 { "Request/Response", "cip.rr",
3023 FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
3024 "Request or Response message", HFILL }
3027 { "Service", "cip.sc",
3028 FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
3029 "Service Code", HFILL }
3033 /* Setup protocol subtree array */
3034 static gint *ett[] = {
3035 &ett_cip_class_generic,
3048 static gint *ett_mr[] = {
3055 static gint *ett_cm[] = {
3063 static gint *ett_cco[] = {
3069 /* Register the protocol name and description */
3070 proto_cip = proto_register_protocol("Common Industrial Protocol",
3073 /* Required function calls to register the header fields and subtrees used */
3074 proto_register_field_array(proto_cip, hf, array_length(hf));
3075 proto_register_subtree_array(ett, array_length(ett));
3076 subdissector_class_table = register_dissector_table("cip.class.iface",
3077 "CIP Class Interface Handle", FT_UINT32, BASE_HEX);
3078 subdissector_symbol_table = register_dissector_table("cip.data_segment.iface",
3079 "CIP Data Segment Interface Handle", FT_UINT32, BASE_HEX);
3081 /* Register the protocol name and description */
3082 proto_cip_class_generic = proto_register_protocol("CIP Class Generic",
3083 "CIPCLS", "cipcls");
3085 /* Register the protocol name and description */
3086 proto_cip_class_mr = proto_register_protocol("CIP Message Router",
3088 proto_register_field_array(proto_cip_class_mr, hf_mr, array_length(hf_mr));
3089 proto_register_subtree_array(ett_mr, array_length(ett_mr));
3091 proto_cip_class_cm = proto_register_protocol("CIP Connection Manager",
3093 proto_register_field_array(proto_cip_class_cm, hf_cm, array_length(hf_cm));
3094 proto_register_subtree_array(ett_cm, array_length(ett_cm));
3096 proto_cip_class_cco = proto_register_protocol("CIP Connection Configuration Object",
3097 "CIPCCO", "cipcco");
3098 proto_register_field_array(proto_cip_class_cco, hf_cco, array_length(hf_cco));
3099 proto_register_subtree_array(ett_cco, array_length(ett_cco));
3101 register_init_routine(&cip_init_protocol);
3102 } /* end of proto_register_cip() */
3106 proto_reg_handoff_cip(void)
3108 /* Create dissector handles */
3109 /* Register for UCMM CIP data, using EtherNet/IP SendRRData service*/
3110 /* Register for Connected CIP data, using EtherNet/IP SendUnitData service*/
3111 cip_handle = new_create_dissector_handle( dissect_cip, proto_cip );
3112 dissector_add( "enip.srrd.iface", ENIP_CIP_INTERFACE, cip_handle );
3113 dissector_add( "enip.sud.iface", ENIP_CIP_INTERFACE, cip_handle );
3115 /* Create and register dissector handle for generic class */
3116 cip_class_generic_handle = new_create_dissector_handle( dissect_cip_class_generic, proto_cip_class_generic );
3117 dissector_add( "cip.class.iface", 0, cip_class_generic_handle );
3119 /* Create and register dissector handle for Message Router */
3120 cip_class_mr_handle = new_create_dissector_handle( dissect_cip_class_mr, proto_cip_class_mr );
3121 dissector_add( "cip.class.iface", CI_CLS_MR, cip_class_mr_handle );
3123 /* Create and register dissector handle for Connection Manager */
3124 cip_class_cm_handle = new_create_dissector_handle( dissect_cip_class_cm, proto_cip_class_cm );
3125 dissector_add( "cip.class.iface", CI_CLS_CM, cip_class_cm_handle );
3127 /* Create and register dissector handle for Connection Configuration Object */
3128 cip_class_cco_handle = new_create_dissector_handle( dissect_cip_class_cco, proto_cip_class_cco );
3129 dissector_add( "cip.class.iface", CI_CLS_CCO, cip_class_cco_handle );
3131 } /* end of proto_reg_handoff_cip() */