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>
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #ifdef NEED_SNPRINTF_H
41 # include "snprintf.h"
44 #include <epan/packet.h>
46 #include "packet-tcp.h"
47 #include "packet-cip.h"
49 #define ENIP_CIP_INTERFACE 0
51 /* Initialize the protocol and registered fields */
52 static int proto_cip = -1;
54 static int hf_cip_sc = -1;
55 static int hf_cip_rr = -1;
56 static int hf_cip_epath = -1;
57 static int hf_cip_genstat = -1;
59 static int hf_cip_fwo_comp = -1;
60 static int hf_cip_fwo_mrev = -1;
61 static int hf_cip_fwo_con_size = -1;
62 static int hf_cip_fwo_fixed_var = -1;
63 static int hf_cip_fwo_prio = -1;
64 static int hf_cip_fwo_typ = -1;
65 static int hf_cip_fwo_own = -1;
66 static int hf_cip_fwo_dir = -1;
67 static int hf_cip_fwo_trigg = -1;
68 static int hf_cip_fwo_class = -1;
70 static int hf_cip_vendor = -1;
71 static int hf_cip_devtype = -1;
72 static int hf_cip_port = -1;
73 static int hf_cip_link_address_byte = -1;
74 static int hf_cip_link_address_string = -1;
75 static int hf_cip_class8 = -1;
76 static int hf_cip_class16 = -1;
77 static int hf_cip_class32 = -1;
78 static int hf_cip_instance8 = -1;
79 static int hf_cip_instance16 = -1;
80 static int hf_cip_instance32 = -1;
81 static int hf_cip_attribute8 = -1;
82 static int hf_cip_attribute16 = -1;
83 static int hf_cip_attribute32 = -1;
84 static int hf_cip_conpoint8 = -1;
85 static int hf_cip_conpoint16 = -1;
86 static int hf_cip_conpoint32 = -1;
87 static int hf_cip_symbol = -1;
89 /* Initialize the subtree pointers */
90 static gint ett_cip = -1;
91 static gint ett_ekey_path = -1;
92 static gint ett_cia_path = -1;
93 static gint ett_data_seg = -1;
94 static gint ett_rrsc = -1;
95 static gint ett_mcsc = -1;
96 static gint ett_ncp = -1;
97 static gint ett_lsrcf = -1;
98 static gint ett_mes_req = -1;
99 static gint ett_cmd_data = -1;
100 static gint ett_port_path = -1;
101 static gint ett_mult_ser = -1;
102 static gint ett_path = -1;
103 static gint ett_status_item = -1;
106 /* Translate function to string - CIP Service codes */
107 static const value_string cip_sc_vals[] = {
108 { SC_GET_ATT_ALL, "Get Attribute All" },
109 { SC_SET_ATT_ALL, "Set Attribute All" },
110 { SC_GET_ATT_LIST, "Get Attribute List" },
111 { SC_SET_ATT_LIST, "Set Attribute List" },
112 { SC_RESET, "Reset" },
113 { SC_START, "Start" },
115 { SC_CREATE, "Create" },
116 { SC_DELETE, "Delete" },
117 { SC_APPLY_ATTRIBUTES, "Apply Attributes" },
118 { SC_GET_ATT_SINGLE, "Get Attribute Single" },
119 { SC_SET_ATT_SINGLE, "Set Attribute Single" },
120 { SC_FIND_NEXT_OBJ_INST, "Find Next Object Instance" },
121 { SC_RESTOR, "Restore" },
124 { SC_GET_MEMBER, "Get Member" },
125 { SC_SET_MEMBER, "Set Member" },
126 { SC_MULT_SERV_PACK, "Multiple Service Packet" },
128 /* Some class specific services */
129 { SC_FWD_CLOSE, "Forward Close" },
130 { SC_FWD_OPEN, "Forward Open" },
131 { SC_UNCON_SEND, "Unconnected Send" },
136 /* Translate function to string - CIP Request/Response */
137 static const value_string cip_sc_rr[] = {
144 /* Translate function to string - Compatibility */
145 static const value_string cip_com_bit_vals[] = {
146 { 0, "Bit Cleared" },
152 /* Translate function to string - Connection priority */
153 static const value_string cip_con_prio_vals[] = {
154 { 0, "Low Priority" },
155 { 1, "High Priority" },
162 /* Translate function to string - Connection size fixed or variable */
163 static const value_string cip_con_fw_vals[] = {
170 /* Translate function to string - Connection owner */
171 static const value_string cip_con_owner_vals[] = {
178 /* Translate function to string - Connection direction */
179 static const value_string cip_con_dir_vals[] = {
186 /* Translate function to string - Production trigger */
187 static const value_string cip_con_trigg_vals[] = {
189 { 1, "Change-Of-State" },
190 { 2, "Application Object" },
195 /* Translate function to string - Transport class */
196 static const value_string cip_con_class_vals[] = {
205 /* Translate function to string - Connection type */
206 static const value_string cip_con_type_vals[] = {
209 { 2, "Point to Point" },
215 /* Translate function to string - Timeout Multiplier */
216 static const value_string cip_con_time_mult_vals[] = {
229 /* Translate function to string - CIP General Status codes */
230 static const value_string cip_gs_vals[] = {
231 { CI_GRC_SUCCESS, "Success" },
232 { CI_GRC_FAILURE, "Connection failure" },
233 { CI_GRC_NO_RESOURCE, "Resource unavailable" },
234 { CI_GRC_BAD_DATA, "Invalid parameter value" },
235 { CI_GRC_BAD_PATH, "Path segment error" },
236 { CI_GRC_BAD_CLASS_INSTANCE, "Path destination unknown" },
237 { CI_GRC_PARTIAL_DATA, "Partial transfer" },
238 { CI_GRC_CONN_LOST, "Connection lost" },
239 { CI_GRC_BAD_SERVICE, "Service not supported" },
240 { CI_GRC_BAD_ATTR_DATA, "Invalid attribute value" },
241 { CI_GRC_ATTR_LIST_ERROR, "Attribute list error" },
242 { CI_GRC_ALREADY_IN_MODE, "Already in requested mode/state" },
243 { CI_GRC_BAD_OBJ_MODE, "Object state conflict" },
244 { CI_GRC_OBJ_ALREADY_EXISTS, "Object already exists" },
245 { CI_GRC_ATTR_NOT_SETTABLE, "Attribute not settable" },
246 { CI_GRC_PERMISSION_DENIED, "Privilege violation" },
247 { CI_GRC_DEV_IN_WRONG_STATE, "Device state conflict" },
248 { CI_GRC_REPLY_DATA_TOO_LARGE,"Reply data too large" },
249 { CI_GRC_FRAGMENT_PRIMITIVE, "Fragmentation of a primitive value" },
250 { CI_GRC_CONFIG_TOO_SMALL, "Not enough data" },
251 { CI_GRC_UNDEFINED_ATTR, "Attribute not supported" },
252 { CI_GRC_CONFIG_TOO_BIG, "Too much data" },
253 { CI_GRC_OBJ_DOES_NOT_EXIST, "Object does not exist" },
254 { CI_GRC_NO_FRAGMENTATION, "Service fragmentation sequence not in progress" },
255 { CI_GRC_DATA_NOT_SAVED, "No stored attribute data" },
256 { CI_GRC_DATA_WRITE_FAILURE, "Store operation failure" },
257 { CI_GRC_REQUEST_TOO_LARGE, "Routing failure, request packet too large" },
258 { CI_GRC_RESPONSE_TOO_LARGE, "Routing failure, response packet too large" },
259 { CI_GRC_MISSING_LIST_DATA, "Missing attribute list entry data" },
260 { CI_GRC_INVALID_LIST_STATUS, "Invalid attribute value list" },
261 { CI_GRC_SERVICE_ERROR, "Embedded service error" },
262 { CI_GRC_CONN_RELATED_FAILURE,"Vendor specific error" },
263 { CI_GRC_INVALID_PARAMETER, "Invalid parameter" },
264 { CI_GRC_WRITE_ONCE_FAILURE, "Write-once value or medium already written" },
265 { CI_GRC_INVALID_REPLY, "Invalid Reply Received" },
266 { CI_GRC_BAD_KEY_IN_PATH, "Key Failure in path" },
267 { CI_GRC_BAD_PATH_SIZE, "Path Size Invalid" },
268 { CI_GRC_UNEXPECTED_ATTR, "Unexpected attribute in list" },
269 { CI_GRC_INVALID_MEMBER, "Invalid Member ID" },
270 { CI_GRC_MEMBER_NOT_SETTABLE, "Member not settable" },
275 /* Translate Vendor ID:s */
276 const value_string cip_vendor_vals[] = {
282 /* Translate Device Profile:s */
283 const value_string cip_devtype_vals[] = {
284 { DP_GEN_DEV, "Generic Device" },
285 { DP_AC_DRIVE, "AC Drive" },
286 { DP_MOTOR_OVERLOAD, "Motor Overload" },
287 { DP_LIMIT_SWITCH, "Limit Switch" },
288 { DP_IND_PROX_SWITCH, "Inductive Proximity Switch" },
289 { DP_PHOTO_SENSOR, "Photoelectric Sensor" },
290 { DP_GENP_DISC_IO, "General Purpose Dicrete I/O" },
291 { DP_RESOLVER, "Resolver" },
292 { DP_COM_ADAPTER, "Communications Adapter" },
293 { DP_POS_CNT, "Position Controller", },
294 { DP_DC_DRIVE, "DC Drive" },
295 { DP_CONTACTOR, "Contactor", },
296 { DP_MOTOR_STARTER, "Motor Starter", },
297 { DP_SOFT_START, "Soft Start", },
298 { DP_HMI, "Human-Machine Interface" },
299 { DP_MASS_FLOW_CNT, "Mass Flow Controller" },
300 { DP_PNEUM_VALVE, "Pneumatic Valve" },
301 { DP_VACUUM_PRES_GAUGE, "Vaccuum Pressure Gauge" },
306 /* Translate class names */
307 static const value_string cip_class_names_vals[] = {
308 { 0x01, "Identity Object" },
309 { 0x02, "Message Router" },
310 { 0x03, "DeviceNet Object" },
311 { 0x04, "Assembly Object" },
312 { 0x05, "Connection Object" },
313 { 0x06, "Connection Manager" },
314 { 0x07, "Register Object" },
315 { 0x08, "Discrete Input Point Object" },
316 { 0x09, "Discrete Output Point Object" },
317 { 0x0A, "Analog Input Point Object" },
318 { 0x0B, "Analog Output Point Object" },
319 { 0x0E, "Presence Sensing Object" },
320 { 0x0F, "Parameter Object" },
321 { 0x10, "Parameter Group Object" },
322 { 0x12, "Group Object" },
323 { 0x1D, "Discrete Input Group Object" },
324 { 0x1E, "Discrete Output Group Object" },
325 { 0x1F, "Discrete Group Object" },
326 { 0x20, "Analog Input Group Object" },
327 { 0x21, "Analog Output Group Object" },
328 { 0x22, "Analog Group Object" },
329 { 0x23, "Position Sensor Object" },
330 { 0x24, "Position Controller Supervisor Object" },
331 { 0x25, "Position Controller Object" },
332 { 0x26, "Block Sequencer Object" },
333 { 0x27, "Command Block Object" },
334 { 0x28, "Motor Data Object" },
335 { 0x29, "Control Supervisor Object" },
336 { 0x2A, "AC/DC Drive Object" },
337 { 0x2B, "Acknowledge Handler Object" },
338 { 0x2C, "Overload Object" },
339 { 0x2D, "Softstart Object" },
340 { 0x2E, "Selection Object" },
341 { 0x30, "S-Device Supervisor Object" },
342 { 0x31, "S-Analog Sensor Object" },
343 { 0x32, "S-Analog Actuator Object" },
344 { 0x33, "S-Single Stage Controller Object" },
345 { 0x34, "S-Gas Calibration Object" },
346 { 0x35, "Trip Point Object" },
347 { 0x37, "File Object" },
348 { 0x38, "S-Partial Pressure Object" },
349 { 0xF0, "ControlNet Object" },
350 { 0xF1, "ControlNet Keeper Object" },
351 { 0xF2, "ControlNet Scheduling Object" },
352 { 0xF3, "Connection Configuration Object" },
353 { 0xF4, "Port Object" },
354 { 0xF5, "TCP/IP Interface Object" },
355 { 0xF6, "EtherNet Link Object" },
362 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
365 char *tmp2, *tmp2start;
367 int i,tmp_length,tmp2_length;
369 /* At least one version of Apple's C compiler/linker is buggy, causing
370 a complaint from the linker about the "literal C string section"
371 not ending with '\0' if we initialize a 16-element "char" array with
372 a 16-character string, the fact that initializing such an array with
373 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
374 '\0' byte in the string nonwithstanding. */
375 static const char my_hex_digits[16] =
376 { '0', '1', '2', '3', '4', '5', '6', '7',
377 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
380 if( ( length * 2 ) > 32 )
388 tmp2_length = ( length * 2 ) + 1;
391 tmp = tvb_get_ptr( tvb, start, tmp_length );
392 tmp2 = (char*)g_malloc( tmp2_length );
396 for( i = 0; i < tmp_length; i++ )
400 *tmp2++ = my_hex_digits[octet&0xF];
402 *tmp2++ = my_hex_digits[octet&0xF];
405 if( tmp_length != length )
414 pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
420 } /* end of add_byte_array_text_to_proto_tree() */
425 dissect_epath( tvbuff_t *tvb, proto_item *epath_item, int offset, int path_length )
427 int pathpos, temp_data, temp_data2, seg_size, i, temp_word;
428 unsigned char segment_type, opt_link_size;
429 proto_tree *path_tree, *port_tree, *net_tree;
430 proto_item *qi, *cia_item, *ds_item;
431 proto_tree *e_key_tree, *cia_tree, *ds_tree;
432 proto_item *mcpi, *port_item, *net_item;
435 /* Create a sub tree for the epath */
436 path_tree = proto_item_add_subtree( epath_item, ett_path );
438 proto_tree_add_item_hidden(path_tree, hf_cip_epath,
439 tvb, offset, path_length, TRUE );
443 while( pathpos < path_length )
445 /* Get segement type */
446 segment_type = tvb_get_guint8( tvb, offset + pathpos );
448 /* Determine the segment type */
450 switch( segment_type & CI_SEGMENT_TYPE_MASK )
452 case CI_PORT_SEGMENT:
454 port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
455 port_tree = proto_item_add_subtree( port_item, ett_port_path );
457 /* Add port number */
458 proto_tree_add_item( port_tree, hf_cip_port, tvb, offset + pathpos, 1, TRUE );
459 proto_item_append_text( epath_item, "Port: %d", ( segment_type & 0x0F ) );
460 proto_item_append_text( port_item, ": Port: %d", ( segment_type & 0x0F ) );
462 if( segment_type & 0x10 )
464 /* Add Extended Link Address flag */
465 proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: TRUE" );
467 /* Add size of extended link address */
468 opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
469 proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size );
471 /* Add extended link address */
472 proto_tree_add_item( port_tree, hf_cip_link_address_string, tvb, offset+pathpos+2, opt_link_size, FALSE );
473 proto_item_append_text( epath_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
474 proto_item_append_text( port_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
477 if( opt_link_size % 2 )
479 proto_item_set_len( port_item, 3 + opt_link_size );
480 pathpos = pathpos + 3 + opt_link_size;
484 proto_item_set_len( port_item, 2 + opt_link_size );
485 pathpos = pathpos + 2 + opt_link_size;
490 /* Add Extended Link Address flag */
491 proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: FALSE" );
493 /* Add Link Address */
494 proto_tree_add_item( port_tree, hf_cip_link_address_byte, tvb, offset+pathpos+1, 1, FALSE );
495 proto_item_append_text( epath_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
496 proto_item_append_text( port_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
498 proto_item_set_len( port_item, 2 );
504 case CI_LOGICAL_SEGMENT:
506 /* Logical segment, determin the logical type */
508 switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
510 case CI_LOGICAL_SEG_CLASS_ID:
512 /* Logical Class ID, do a format check */
514 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
516 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
517 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Class Segment (0x%02X)", segment_type );
519 /* Create a sub tree for the class */
520 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
522 /* Display the 8-bit class number */
523 proto_tree_add_item( cia_tree, hf_cip_class8, tvb, offset + pathpos + 1, 1, TRUE );
524 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%02X" ) );
526 /* 2 bytes of path used */
529 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
531 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
532 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Class Segment (0x%02X)", segment_type );
534 /* Create a sub tree for the class */
535 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
537 /* Display the 16-bit class number */
538 proto_tree_add_item( cia_tree, hf_cip_class16, tvb, offset + pathpos + 2, 2, TRUE );
539 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%04X" ) );
541 /* 4 bytes of path used */
544 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
546 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
547 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
549 /* Create a sub tree for the class */
550 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
552 /* Display the 32-bit class number */
553 proto_tree_add_item( cia_tree, hf_cip_class32, tvb, offset + pathpos + 2, 4, TRUE );
554 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%08X" ) );
556 /* 6 bytes of path used */
561 /* Unsupported logical segment format */
562 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
568 case CI_LOGICAL_SEG_INST_ID:
570 /* Logical Instance ID, do a format check */
572 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
574 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
575 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
577 /* Create a sub tree for the instance */
578 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
580 /* Display the 8-bit instance number */
581 proto_tree_add_item( cia_tree, hf_cip_instance8, tvb, offset + pathpos + 1, 1, TRUE );
582 proto_item_append_text( epath_item, "Instance: 0x%02X", temp_data );
584 /* 2 bytes of path used */
587 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
589 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
590 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
592 /* Create a sub tree for the instance */
593 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
595 /* Display the 16-bit instance number */
596 proto_tree_add_item( cia_tree, hf_cip_instance16, tvb, offset + pathpos + 2, 2, TRUE );
597 proto_item_append_text( epath_item, "Instance: 0x%04X", temp_data );
599 /* 4 bytes of path used */
602 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
604 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
605 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
607 /* Create a sub tree for the instance */
608 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
610 /* Display the 32-bit instance number */
611 proto_tree_add_item( cia_tree, hf_cip_instance32, tvb, offset + pathpos + 2, 4, TRUE );
612 proto_item_append_text( epath_item, "Instance: 0x%08X", temp_data );
615 /* 6 bytes of path used */
620 /* Unsupported logical segment format */
621 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
627 case CI_LOGICAL_SEG_ATTR_ID:
629 /* Logical Attribute ID, do a format check */
631 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
633 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
634 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
636 /* Create a sub tree for the attribute */
637 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
639 /* Display the 8-bit attribute number */
640 proto_tree_add_item( cia_tree, hf_cip_attribute8, tvb, offset + pathpos + 1, 1, TRUE );
641 proto_item_append_text( epath_item, "Attribute: 0x%02X", temp_data );
643 /* 2 bytes of path used */
646 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
648 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
649 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
651 /* Create a sub tree for the attribute */
652 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
654 /* Display the 16-bit attribute number */
655 proto_tree_add_item( cia_tree, hf_cip_attribute16, tvb, offset + pathpos + 2, 2, TRUE );
656 proto_item_append_text( epath_item, "Attribute: 0x%04X", temp_data );
658 /* 4 bytes of path used */
661 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
663 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
664 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
666 /* Create a sub tree for the attribute */
667 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
669 /* Display the 32-bit attribute number */
670 proto_tree_add_item( cia_tree, hf_cip_attribute32, tvb, offset + pathpos + 2, 4, TRUE );
671 proto_item_append_text( epath_item, "Attribute: 0x%08X", temp_data );
673 /* 6 bytes of path used */
678 /* Unsupported logical segment format */
679 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
685 case CI_LOGICAL_SEG_CON_POINT:
687 /* Logical Connection point , do a format check */
689 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
691 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
692 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Connection Point Segment (0x%02X)", segment_type );
694 /* Create a sub tree for the connection point */
695 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
697 /* Display the 8-bit connection point number */
698 proto_tree_add_item( cia_tree, hf_cip_conpoint8, tvb, offset + pathpos + 1, 1, TRUE );
699 proto_item_append_text( epath_item, "Connection Point: 0x%02X", temp_data );
701 /* 2 bytes of path used */
704 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
706 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
707 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Connection Point Segment (0x%02X)", segment_type );
709 /* Create a sub tree for the connection point */
710 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
712 /* Display the 16-bit connection point number */
713 proto_tree_add_item( cia_tree, hf_cip_conpoint16, tvb, offset + pathpos + 2, 2, TRUE );
714 proto_item_append_text( epath_item, "Connection Point: 0x%04X", temp_data );
716 /* 4 bytes of path used */
719 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
721 temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
722 cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Connection Point Segment (0x%02X)", segment_type );
724 /* Create a sub tree for the connection point */
725 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
727 /* Display the 32-bit connection point number */
728 proto_tree_add_item( cia_tree, hf_cip_conpoint32, tvb, offset + pathpos + 2, 4, TRUE );
729 proto_item_append_text( epath_item, "Connection Point: 0x%08X", temp_data );
731 /* 6 bytes of path used */
736 /* Unsupported logical segment format */
737 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
743 case CI_LOGICAL_SEG_SPECIAL:
745 /* Logical Special ID, the only logical format sepcifyed is electronic key */
747 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
749 /* Get the Key Format */
750 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
752 if( temp_data == CI_E_KEY_FORMAT_VAL )
754 qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
756 /* Create a sub tree for the IOI */
757 e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
759 /* Print the key type */
760 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
762 /* Get the Vendor ID */
763 temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
764 proto_tree_add_item( e_key_tree, hf_cip_vendor, tvb, offset + pathpos + 2, 2, TRUE);
765 proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
767 /* Get Device Type */
768 temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
769 proto_tree_add_item( e_key_tree, hf_cip_devtype, tvb, offset + pathpos + 4, 2, TRUE);
770 proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
773 temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
774 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
776 /* Major revision/Compatibility */
777 temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
779 /* Add Major revision/Compatibility tree */
780 mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
781 mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
783 /* Add Compatibility bit info */
784 proto_tree_add_item(mc_tree, hf_cip_fwo_comp,
785 tvb, offset + pathpos + 8, 1, TRUE );
787 proto_item_append_text( mcpi, "%s, Major Revision: %d",
788 val_to_str( ( temp_data & 0x80 )>>7, cip_com_bit_vals , "" ),
792 proto_tree_add_item(mc_tree, hf_cip_fwo_mrev,
793 tvb, offset + pathpos + 8, 1, TRUE );
796 temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
797 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
799 proto_item_append_text( qi, ", %d.%d", ( temp_data & 0x7F ), temp_data2 );
801 proto_item_append_text(epath_item, "[Key]" );
803 /* Increment the path pointer */
808 /* Unsupported electronic key format */
809 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
815 /* Unsupported special segment format */
816 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
823 /* Unsupported logical segment type */
824 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
827 } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
831 case CI_DATA_SEGMENT:
833 /* Data segment, determin the logical type */
835 switch( segment_type )
837 case CI_DATA_SEG_SIMPLE:
839 /* Simple data segment */
840 ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
842 /* Create a sub tree */
843 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
846 seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
847 proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
852 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
854 for( i=0; i < seg_size/2; i ++ )
856 temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
857 proto_item_append_text(qi, " 0x%04X", temp_word );
860 proto_item_set_len(qi, seg_size);
863 proto_item_set_len( ds_item, 2 + seg_size );
864 pathpos = pathpos + 2 + seg_size;
866 proto_item_append_text(epath_item, "[Data]" );
870 case CI_DATA_SEG_SYMBOL:
872 /* ANSI extended symbol segment */
873 ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
875 /* Create a sub tree */
876 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
879 seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
880 proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
885 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2, seg_size, "Data: %s",
886 tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
888 proto_item_append_text(epath_item, "%s", tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
889 proto_tree_add_item_hidden( ds_tree, hf_cip_symbol, tvb, offset + pathpos + 2, seg_size, FALSE );
893 /* We have a PAD BYTE */
894 proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2 + seg_size, 1, "Pad Byte (0x%02X)",
895 tvb_get_guint8( tvb, offset + pathpos + 2 + seg_size ) );
901 proto_item_set_len( ds_item, 2 + seg_size );
902 pathpos = pathpos + 2 + seg_size;
907 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
910 } /* End of switch sub-type */
914 case CI_NETWORK_SEGMENT:
916 /* Network segment -Determine the segment sub-type */
918 switch( segment_type & CI_NETWORK_SEG_TYPE_MASK )
920 case CI_NETWORK_SEG_SCHEDULE:
921 net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Schedule" );
922 net_tree = proto_item_add_subtree( net_item, ett_port_path );
924 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Multiplier/Phase: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
926 /* 2 bytes of path used */
930 case CI_NETWORK_SEG_FIXED_TAG:
931 net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Fixed Tag" );
932 net_tree = proto_item_add_subtree( net_item, ett_port_path );
934 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Fixed Tag: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
936 /* 2 bytes of path used */
940 case CI_NETWORK_SEG_PROD_INHI:
941 net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Production Inhibit" );
942 net_tree = proto_item_add_subtree( net_item, ett_port_path );
944 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Production Inhibit Time: %dms", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
946 /* 2 bytes of path used */
951 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
954 } /* End of switch sub-type */
960 /* Unsupported segment type */
961 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
964 } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
966 /* Next path segment */
967 if( pathpos < path_length )
968 proto_item_append_text( epath_item, ", " );
970 } /* end of while( pathpos < path_length ) */
972 } /* end of dissect_epath() */
976 dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
978 proto_item *pi, *rrsc_item, *ncppi, *ar_item, *temp_item, *temp_item2, *status_item;
979 proto_tree *temp_tree, *rrsc_tree, *ncp_tree, *cmd_data_tree, *status_tree;
980 int req_path_size, conn_path_size, temp_data;
981 unsigned char gen_status;
982 unsigned char add_stat_size;
983 unsigned char temp_byte, route_path_size;
984 unsigned char app_rep_size, i;
985 int msg_req_siz, num_services, serv_offset;
988 /* Add Service code & Request/Response tree */
989 rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
990 rrsc_tree = proto_item_add_subtree( rrsc_item, ett_rrsc );
992 /* Add Request/Response */
993 proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
995 proto_item_append_text( rrsc_item, "%s (%s)",
996 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
997 cip_sc_vals , "Unknown Service (%x)"),
998 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
1001 /* Add Service code */
1002 proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
1004 if( tvb_get_guint8( tvb, offset ) & 0x80 )
1006 /* Response message */
1007 status_item = proto_tree_add_text( item_tree, tvb, offset+2, 1, "Status: " );
1008 status_tree = proto_item_add_subtree( status_item, ett_status_item );
1010 /* Add general status */
1011 gen_status = tvb_get_guint8( tvb, offset+2 );
1012 proto_tree_add_item(status_tree, hf_cip_genstat, tvb, offset+2, 1, TRUE );
1013 proto_item_append_text( status_item, "%s", val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
1014 cip_gs_vals , "Unknown Response (%x)") );
1016 /* Add reply status to info column */
1017 if(check_col(pinfo->cinfo, COL_INFO))
1019 col_append_fstr( pinfo->cinfo, COL_INFO, "%s",
1020 val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
1021 cip_gs_vals , "Unknown Response (%x)") );
1024 /* Add additional status size */
1025 proto_tree_add_text( status_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)",
1026 tvb_get_guint8( tvb, offset+3 ) );
1028 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
1032 proto_item_append_text( status_item, ", Extended:" );
1034 /* Add additional status */
1035 pi = proto_tree_add_text( status_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
1037 for( i=0; i < add_stat_size/2; i ++ )
1039 proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
1040 proto_item_append_text( status_item, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
1044 proto_item_set_len( status_item, 2 + add_stat_size );
1046 /* If there is any command specific data create a sub-tree for it */
1047 if( ( item_length-4-add_stat_size ) != 0 )
1049 pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific data" );
1050 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1052 if( gen_status == CI_GRC_SUCCESS )
1054 /* Success responses */
1056 if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN )
1058 /* Forward open Response (Success) */
1060 /* Display originator to target connection ID */
1061 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size );
1062 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1064 /* Display target to originator connection ID */
1065 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1066 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1068 /* Display connection serial number */
1069 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
1070 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", temp_data );
1072 /* Display the originator vendor id */
1073 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+10, 2, TRUE);
1075 /* Display the originator serial number */
1076 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
1077 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", temp_data );
1079 /* Display originator to target actual packet interval */
1080 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
1081 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 );
1083 /* Display originator to target actual packet interval */
1084 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
1085 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 );
1087 /* Display the application reply size */
1088 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
1089 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1091 /* Display the Reserved byte */
1092 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
1093 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
1095 if( app_rep_size != 0 )
1097 /* Display application Reply data */
1098 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
1100 for( i=0; i < app_rep_size; i++ )
1102 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
1103 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1106 } /* End of if reply data */
1108 } /* End of if forward open response */
1109 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE )
1111 /* Forward close response (Success) */
1113 /* Display connection serial number */
1114 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1115 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1117 /* Display the originator vendor id */
1118 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
1120 /* Display the originator serial number */
1121 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1122 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1124 /* Display the application reply size */
1125 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
1126 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1128 /* Display the Reserved byte */
1129 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1130 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
1132 if( app_rep_size != 0 )
1134 /* Display application Reply data */
1135 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
1137 for( i=0; i < app_rep_size; i ++ )
1139 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
1140 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1143 } /* End of if reply data */
1145 } /* End of if forward close response */
1146 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1148 /* Unconnected send response (Success) */
1150 /* Display service response data */
1151 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1153 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
1155 /* Multiple Service Reply (Success)*/
1157 /* Add number of replies */
1158 num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
1159 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
1162 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
1164 for( i=0; i < num_services; i++ )
1168 serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
1170 if( i == (num_services-1) )
1172 /* Last service to add */
1173 proto_item_append_text(temp_item, "%d", serv_offset );
1174 serv_length = item_length-add_stat_size-serv_offset-4;
1178 proto_item_append_text(temp_item, "%d, ", serv_offset );
1179 serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
1182 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
1183 temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1186 ** We call our selves again to disect embedded packet
1189 if(check_col(pinfo->cinfo, COL_INFO))
1190 col_append_fstr( pinfo->cinfo, COL_INFO, ", ");
1192 dissect_cip_data( temp_tree, tvb, offset+serv_offset+4, serv_length, pinfo );
1194 } /* End if Multiple service Packet */
1195 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
1197 /* Get Attribute List Reply (Success)*/
1201 /* Add Attribute Count */
1202 att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
1203 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
1206 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
1208 } /* End if Multiple service Packet */
1212 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1213 } /* end of check service code */
1218 /* Error responses */
1220 if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN ) ||
1221 ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE ) )
1223 /* Forward open and forward close error response look the same */
1225 /* Display connection serial number */
1226 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1227 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1229 /* Display the originator vendor id */
1230 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
1232 /* Display the originator serial number */
1233 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1234 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1236 /* Display remaining path size */
1237 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
1238 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
1240 /* Display reserved data */
1241 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1242 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
1244 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1246 /* Unconnected send response (Unsuccess) */
1248 /* Display remaining path size */
1249 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
1250 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
1255 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1258 } /* end of if-else( CI_CRC_SUCCESS ) */
1260 } /* End of if command-specific data present */
1262 } /* End of if reply */
1265 /* Request message */
1267 /* Add service to info column */
1268 if(check_col(pinfo->cinfo, COL_INFO))
1270 col_append_fstr( pinfo->cinfo, COL_INFO, "%s",
1271 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1272 cip_sc_vals , "Unknown Service (%x)") );
1275 /* Add path size to tree */
1276 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
1277 proto_tree_add_text( item_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
1280 pi = proto_tree_add_text(item_tree, tvb, offset+2, req_path_size, "Request Path: ");
1281 dissect_epath( tvb, pi, offset+2, req_path_size );
1283 /* If there is any command specific data creat a sub-tree for it */
1284 if( (item_length-req_path_size-2) != 0 )
1287 pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
1288 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1290 /* Check what service code that recived */
1292 if( tvb_get_guint8( tvb, offset ) == SC_FWD_OPEN )
1294 /* Forward open Request*/
1296 /* Display the priority/tick timer */
1297 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1298 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1300 /* Display the time-out ticks */
1301 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1302 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1304 /* Display the actual time out */
1305 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1306 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1308 /* Display originator to taget connection ID */
1309 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
1310 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1312 /* Display target to originator connection ID */
1313 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1314 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1316 /* Display connection serial number */
1317 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
1318 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
1320 /* Display the originator vendor id */
1321 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+12, 2, TRUE);
1323 /* Display the originator serial number */
1324 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
1325 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
1327 /* Display the timeout multiplier */
1328 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
1329 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 );
1331 /* Put out an indicator for the reserved bytes */
1332 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
1334 /* Display originator to target requested packet interval */
1335 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
1336 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 );
1338 /* Display originator to target network connection patameterts, in a tree */
1339 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
1340 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 );
1341 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1343 /* Add the data to the tree */
1344 proto_tree_add_item(ncp_tree, hf_cip_fwo_own,
1345 tvb, offset+2+req_path_size+26, 2, TRUE );
1346 proto_tree_add_item(ncp_tree, hf_cip_fwo_typ,
1347 tvb, offset+2+req_path_size+26, 2, TRUE );
1348 proto_tree_add_item(ncp_tree, hf_cip_fwo_prio,
1349 tvb, offset+2+req_path_size+26, 2, TRUE );
1350 proto_tree_add_item(ncp_tree, hf_cip_fwo_fixed_var,
1351 tvb, offset+2+req_path_size+26, 2, TRUE );
1352 proto_tree_add_item(ncp_tree, hf_cip_fwo_con_size,
1353 tvb, offset+2+req_path_size+26, 2, TRUE );
1355 /* Display target to originator requested packet interval */
1356 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
1357 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 );
1359 /* Display target to originator network connection patameterts, in a tree */
1360 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
1361 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 );
1362 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1364 /* Add the data to the tree */
1365 proto_tree_add_item(ncp_tree, hf_cip_fwo_own,
1366 tvb, offset+2+req_path_size+32, 2, TRUE );
1367 proto_tree_add_item(ncp_tree, hf_cip_fwo_typ,
1368 tvb, offset+2+req_path_size+32, 2, TRUE );
1369 proto_tree_add_item(ncp_tree, hf_cip_fwo_prio,
1370 tvb, offset+2+req_path_size+32, 2, TRUE );
1371 proto_tree_add_item(ncp_tree, hf_cip_fwo_fixed_var,
1372 tvb, offset+2+req_path_size+32, 2, TRUE );
1373 proto_tree_add_item(ncp_tree, hf_cip_fwo_con_size,
1374 tvb, offset+2+req_path_size+32, 2, TRUE );
1376 /* Transport type/trigger in tree*/
1377 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
1379 ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
1380 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1382 /* Add the data to the tree */
1383 proto_tree_add_item(ncp_tree, hf_cip_fwo_dir,
1384 tvb, offset+2+req_path_size+34, 1, TRUE );
1386 proto_tree_add_item(ncp_tree, hf_cip_fwo_trigg,
1387 tvb, offset+2+req_path_size+34, 1, TRUE );
1389 proto_tree_add_item(ncp_tree, hf_cip_fwo_class,
1390 tvb, offset+2+req_path_size+34, 1, TRUE );
1393 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
1394 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1397 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
1398 dissect_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size );
1400 else if( tvb_get_guint8( tvb, offset ) == SC_FWD_CLOSE )
1402 /* Forward Close Request */
1404 /* Display the priority/tick timer */
1405 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1406 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1408 /* Display the time-out ticks */
1409 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1410 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1412 /* Display the actual time out */
1413 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1414 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1416 /* Display connection serial number */
1417 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1418 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
1420 /* Display the originator vendor id */
1421 proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+4, 2, TRUE);
1423 /* Display the originator serial number */
1424 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1425 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
1427 /* Add the path size */
1428 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
1429 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1431 /* Add the reserved byte */
1432 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
1433 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
1436 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
1437 dissect_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size );
1439 } /* End of forward close */
1440 else if( tvb_get_guint8( tvb, offset ) == SC_UNCON_SEND )
1442 /* Unconnected send */
1444 /* Display the priority/tick timer */
1445 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1446 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1448 /* Display the time-out ticks */
1449 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1450 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1452 /* Display the actual time out */
1453 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1454 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1456 /* Message request size */
1457 msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1458 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
1460 /* Message Request */
1461 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
1462 temp_tree = proto_item_add_subtree(temp_item, ett_mes_req );
1465 ** We call our selves again to disect embedded packet
1468 if(check_col(pinfo->cinfo, COL_INFO))
1469 col_append_fstr( pinfo->cinfo, COL_INFO, ": ");
1471 dissect_cip_data( temp_tree, tvb, offset+2+req_path_size+4, msg_req_siz, pinfo );
1473 if( msg_req_siz % 2 )
1476 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
1477 tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
1478 msg_req_siz++; /* include the padding */
1481 /* Route Path Size */
1482 route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
1483 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 );
1486 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
1487 tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
1490 temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path: ");
1491 dissect_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size );
1493 } /* End if unconnected send */
1494 else if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
1496 /* Multiple service packet */
1498 /* Add number of services */
1499 num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
1500 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
1503 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
1505 for( i=0; i < num_services; i++ )
1509 serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
1511 if( i == (num_services-1) )
1513 /* Last service to add */
1514 serv_length = item_length-2-req_path_size-serv_offset;
1515 proto_item_append_text(temp_item, "%d", serv_offset );
1519 serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
1520 proto_item_append_text(temp_item, "%d, ", serv_offset );
1523 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
1524 temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1527 ** We call our selves again to disect embedded packet
1530 if(check_col(pinfo->cinfo, COL_INFO))
1531 col_append_fstr( pinfo->cinfo, COL_INFO, ", ");
1533 dissect_cip_data( temp_tree, tvb, offset+serv_offset+6, serv_length, pinfo );
1535 } /* End if Multiple service Packet */
1536 else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
1538 /* Get attribute list request */
1542 /* Add number of services */
1543 att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
1544 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
1546 /* Add Attribute List */
1547 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
1549 for( i=0; i < att_count; i++ )
1551 if( i == (att_count-1) )
1552 proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1554 proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1557 } /* End of Get attribute list request */
1561 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
1562 } /* End of check service code */
1564 } /* End of if command-specific data present */
1566 } /* End of if-else( request ) */
1568 } /* End of dissect_cip_data() */
1572 dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1575 proto_tree *cip_tree;
1577 /* Make entries in Protocol column and Info column on summary display */
1578 if( check_col( pinfo->cinfo, COL_PROTOCOL ) )
1579 col_set_str( pinfo->cinfo, COL_PROTOCOL, "CIP" );
1581 if (check_col( pinfo->cinfo, COL_INFO ) )
1582 col_clear( pinfo->cinfo, COL_INFO );
1586 /* Create display subtree for the protocol */
1587 ti = proto_tree_add_item(tree, proto_cip, tvb, 0, -1, FALSE);
1588 cip_tree = proto_item_add_subtree( ti, ett_cip );
1590 dissect_cip_data( cip_tree, tvb, 0, tvb_length(tvb), pinfo );
1593 return tvb_length(tvb);
1598 proto_register_cip(void)
1600 /* Setup list of header fields */
1601 static hf_register_info hf[] = {
1604 { "Request/Response", "cip.rr",
1605 FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
1606 "Request or Response message", HFILL }
1609 { "Service", "cip.sc",
1610 FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
1611 "Service Code", HFILL }
1614 { "EPath", "cip.epath",
1615 FT_BYTES, BASE_HEX, NULL, 0,
1619 { "General Status", "cip.genstat",
1620 FT_UINT8, BASE_HEX, VALS(cip_gs_vals), 0,
1621 "General Status", HFILL }
1624 { "Port", "cip.port",
1625 FT_UINT8, BASE_DEC, NULL, 0,
1626 "Port Identifier", HFILL }
1628 { &hf_cip_link_address_byte,
1629 { "Link Address", "cip.linkaddress",
1630 FT_UINT8, BASE_DEC, NULL, 0,
1631 "Link Address", HFILL }
1633 { &hf_cip_link_address_string,
1634 { "Link Address", "cip.linkaddress",
1635 FT_STRING, BASE_NONE, NULL, 0,
1636 "Link Address", HFILL }
1639 { "Class", "cip.class",
1640 FT_UINT8, BASE_HEX, VALS(cip_class_names_vals), 0,
1644 { "Class", "cip.class",
1645 FT_UINT16, BASE_HEX, VALS(cip_class_names_vals), 0,
1649 { "Class", "cip.class",
1650 FT_UINT32, BASE_HEX, VALS(cip_class_names_vals), 0,
1653 { &hf_cip_instance8,
1654 { "Instance", "cip.instance",
1655 FT_UINT8, BASE_HEX, NULL, 0,
1658 { &hf_cip_instance16,
1659 { "Instance", "cip.instance",
1660 FT_UINT16, BASE_HEX, NULL, 0,
1663 { &hf_cip_instance32,
1664 { "Instance", "cip.instance",
1665 FT_UINT32, BASE_HEX, NULL, 0,
1668 { &hf_cip_attribute8,
1669 { "Attribute", "cip.attribute",
1670 FT_UINT8, BASE_HEX, NULL, 0,
1671 "Attribute", HFILL }
1673 { &hf_cip_attribute16,
1674 { "Attribute", "cip.attribute",
1675 FT_UINT16, BASE_HEX, NULL, 0,
1676 "Attribute", HFILL }
1678 { &hf_cip_attribute32,
1679 { "Attribute", "cip.attribute",
1680 FT_UINT32, BASE_HEX, NULL, 0,
1681 "Attribute", HFILL }
1683 { &hf_cip_conpoint8,
1684 { "Connection Point", "cip.connpoint",
1685 FT_UINT8, BASE_HEX, NULL, 0,
1686 "Connection Point", HFILL }
1688 { &hf_cip_conpoint16,
1689 { "Connection Point", "cip.connpoint",
1690 FT_UINT16, BASE_HEX, NULL, 0,
1691 "Connection Point", HFILL }
1693 { &hf_cip_conpoint32,
1694 { "Connection Point", "cip.connpoint",
1695 FT_UINT16, BASE_HEX, NULL, 0,
1696 "Connection Point", HFILL }
1699 { "Symbol", "cip.symbol",
1700 FT_STRING, BASE_NONE, NULL, 0,
1701 "ANSI Extended Symbol Segment", HFILL }
1704 { "Vendor ID", "cip.vendor",
1705 FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
1706 "Vendor ID", HFILL }
1709 { "Device Type", "cip.devtype",
1710 FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
1711 "Device Type", HFILL }
1714 { "Compatibility", "cip.fwo.cmp",
1715 FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80,
1716 "Fwd Open: Compatibility bit", HFILL }
1719 { "Major Revision", "cip.fwo.major",
1720 FT_UINT8, BASE_DEC, NULL, 0x7F,
1721 "Fwd Open: Major Revision", HFILL }
1723 { &hf_cip_fwo_con_size,
1724 { "Connection Size", "cip.fwo.consize",
1725 FT_UINT16, BASE_DEC, NULL, 0x01FF,
1726 "Fwd Open: Connection size", HFILL }
1728 { &hf_cip_fwo_fixed_var,
1729 { "Connection Size Type", "cip.fwo.f_v",
1730 FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200,
1731 "Fwd Open: Fixed or variable connection size", HFILL }
1734 { "Priority", "cip.fwo.prio",
1735 FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00,
1736 "Fwd Open: Connection priority", HFILL }
1739 { "Connection Type", "cip.fwo.type",
1740 FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000,
1741 "Fwd Open: Connection type", HFILL }
1744 { "Owner", "cip.fwo.owner",
1745 FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000,
1746 "Fwd Open: Redundant owner bit", HFILL }
1749 { "Direction", "cip.fwo.dir",
1750 FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), 0x80,
1751 "Fwd Open: Direction", HFILL }
1753 { &hf_cip_fwo_trigg,
1754 { "Trigger", "cip.fwo.trigger",
1755 FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), 0x70,
1756 "Fwd Open: Production trigger", HFILL }
1758 { &hf_cip_fwo_class,
1759 { "Class", "cip.fwo.transport",
1760 FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), 0x0F,
1761 "Fwd Open: Transport Class", HFILL }
1765 /* Setup protocol subtree array */
1766 static gint *ett[] = {
1784 /* Register the protocol name and description */
1785 proto_cip = proto_register_protocol("Common Industrial Protocol",
1788 /* Required function calls to register the header fields and subtrees used */
1789 proto_register_field_array(proto_cip, hf, array_length(hf));
1790 proto_register_subtree_array(ett, array_length(ett));
1792 } /* end of proto_register_cip() */
1796 proto_reg_handoff_cip(void)
1798 dissector_handle_t cip_handle;
1800 /* Create dissector handles */
1801 cip_handle = new_create_dissector_handle( dissect_cip, proto_cip );
1803 /* Register for UCMM CIP data, using EtherNet/IP SendRRData service*/
1804 dissector_add( "enip.srrd.iface", ENIP_CIP_INTERFACE, cip_handle );
1806 /* Register for Connected CIP data, using EtherNet/IP SendUnitData service*/
1807 dissector_add( "enip.sud.iface", ENIP_CIP_INTERFACE, cip_handle );
1809 } /* end of proto_reg_handoff_cip() */