various code cleanup:
[obnox/wireshark/wip.git] / epan / dissectors / packet-cip.c
1 /* packet-cip.c
2  * Routines for Common Industrial Protocol (CIP) dissection
3  * CIP Home: www.odva.org
4  *
5  * Copyright 2004
6  * Magnus Hansson <mah@hms.se>
7  * Joakim Wiberg <jow@hms.se>
8  *
9  * $Id$
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
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.
19  *
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.
24  *
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.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <glib.h>
39
40 #include <epan/packet.h>
41 #include <prefs.h>
42 #include "packet-tcp.h"
43 #include "packet-cip.h"
44
45 #define  ENIP_CIP_INTERFACE   0
46
47 /* Initialize the protocol and registered fields */
48 static int proto_cip              = -1;
49
50 static int hf_cip_sc              = -1;
51 static int hf_cip_rr              = -1;
52 static int hf_cip_epath           = -1;
53 static int hf_cip_genstat         = -1;
54
55 static int hf_cip_fwo_comp        = -1;
56 static int hf_cip_fwo_mrev        = -1;
57 static int hf_cip_fwo_con_size    = -1;
58 static int hf_cip_fwo_fixed_var   = -1;
59 static int hf_cip_fwo_prio        = -1;
60 static int hf_cip_fwo_typ         = -1;
61 static int hf_cip_fwo_own         = -1;
62 static int hf_cip_fwo_dir         = -1;
63 static int hf_cip_fwo_trigg       = -1;
64 static int hf_cip_fwo_class       = -1;
65
66 static int hf_cip_vendor              = -1;
67 static int hf_cip_devtype             = -1;
68 static int hf_cip_port                = -1;
69 static int hf_cip_link_address_byte   = -1;
70 static int hf_cip_link_address_string = -1;
71 static int hf_cip_class8              = -1;
72 static int hf_cip_class16             = -1;
73 static int hf_cip_class32             = -1;
74 static int hf_cip_instance8           = -1;
75 static int hf_cip_instance16          = -1;
76 static int hf_cip_instance32          = -1;
77 static int hf_cip_attribute8          = -1;
78 static int hf_cip_attribute16         = -1;
79 static int hf_cip_attribute32         = -1;
80 static int hf_cip_conpoint8           = -1;
81 static int hf_cip_conpoint16          = -1;
82 static int hf_cip_conpoint32          = -1;
83 static int hf_cip_symbol              = -1;
84
85 /* Initialize the subtree pointers */
86 static gint ett_cip           = -1;
87 static gint ett_ekey_path     = -1;
88 static gint ett_cia_path      = -1;
89 static gint ett_data_seg      = -1;
90 static gint ett_rrsc          = -1;
91 static gint ett_mcsc          = -1;
92 static gint ett_ncp           = -1;
93 static gint ett_lsrcf         = -1;
94 static gint ett_mes_req       = -1;
95 static gint ett_cmd_data      = -1;
96 static gint ett_port_path     = -1;
97 static gint ett_mult_ser      = -1;
98 static gint ett_path          = -1;
99 static gint ett_status_item   = -1;
100
101
102 /* Translate function to string - CIP Service codes */
103 static const value_string cip_sc_vals[] = {
104         { SC_GET_ATT_ALL,                "Get Attribute All" },
105         { SC_SET_ATT_ALL,                "Set Attribute All" },
106         { SC_GET_ATT_LIST,            "Get Attribute List" },
107         { SC_SET_ATT_LIST,            "Set Attribute List" },
108         { SC_RESET,                    "Reset" },
109    { SC_START,                 "Start" },
110    { SC_STOP,                  "Stop" },
111    { SC_CREATE,             "Create" },
112    { SC_DELETE,             "Delete" },
113    { SC_APPLY_ATTRIBUTES,          "Apply Attributes" },
114         { SC_GET_ATT_SINGLE,          "Get Attribute Single" },
115         { SC_SET_ATT_SINGLE,          "Set Attribute Single" },
116    { SC_FIND_NEXT_OBJ_INST,     "Find Next Object Instance" },
117    { SC_RESTOR,             "Restore" },
118         { SC_SAVE,                     "Save" },
119         { SC_NO_OP,                    "Nop" },
120         { SC_GET_MEMBER,                 "Get Member" },
121         { SC_SET_MEMBER,                 "Set Member" },
122         { SC_MULT_SERV_PACK,       "Multiple Service Packet" },
123
124         /* Some class specific services */
125         { SC_FWD_CLOSE,          "Forward Close" },
126         { SC_FWD_OPEN,              "Forward Open" },
127         { SC_UNCON_SEND,           "Unconnected Send" },
128
129         { 0,                                        NULL }
130 };
131
132 /* Translate function to string - CIP Request/Response */
133 static const value_string cip_sc_rr[] = {
134         { 0,          "Request"  },
135         { 1,          "Response" },
136
137         { 0,                    NULL }
138 };
139
140 /* Translate function to string - Compatibility */
141 static const value_string cip_com_bit_vals[] = {
142         { 0,          "Bit Cleared" },
143         { 1,          "Bit Set"     },
144
145         { 0,        NULL          }
146 };
147
148 /* Translate function to string - Connection priority */
149 static const value_string cip_con_prio_vals[] = {
150         { 0,          "Low Priority"  },
151         { 1,          "High Priority" },
152         { 2,          "Scheduled"     },
153         { 3,          "Urgent"        },
154
155         { 0,        NULL            }
156 };
157
158 /* Translate function to string - Connection size fixed or variable */
159 static const value_string cip_con_fw_vals[] = {
160         { 0,          "Fixed"    },
161         { 1,          "Variable" },
162
163         { 0,        NULL       }
164 };
165
166 /* Translate function to string - Connection owner */
167 static const value_string cip_con_owner_vals[] = {
168         { 0,          "Exclusive" },
169         { 1,          "Redundant" },
170
171         { 0,        NULL        }
172 };
173
174 /* Translate function to string - Connection direction */
175 static const value_string cip_con_dir_vals[] = {
176         { 0,          "Client" },
177         { 1,          "Server" },
178
179         { 0,        NULL        }
180 };
181
182 /* Translate function to string - Production trigger */
183 static const value_string cip_con_trigg_vals[] = {
184         { 0,          "Cyclic" },
185         { 1,          "Change-Of-State" },
186         { 2,          "Application Object" },
187
188         { 0,        NULL        }
189 };
190
191 /* Translate function to string - Transport class */
192 static const value_string cip_con_class_vals[] = {
193         { 0,          "0" },
194         { 1,          "1" },
195         { 2,          "2" },
196         { 3,          "3" },
197
198         { 0,        NULL        }
199 };
200
201 /* Translate function to string - Connection type */
202 static const value_string cip_con_type_vals[] = {
203         { 0,          "Null"           },
204         { 1,          "Multicast"      },
205         { 2,          "Point to Point" },
206         { 3,          "Reserved"       },
207
208         { 0,        NULL             }
209 };
210
211 /* Translate function to string - Timeout Multiplier */
212 static const value_string cip_con_time_mult_vals[] = {
213         { 0,        "*4"   },
214         { 1,        "*8"   },
215         { 2,        "*16"  },
216         { 3,        "*32"  },
217         { 4,        "*64"  },
218         { 5,        "*128" },
219         { 6,        "*256" },
220         { 7,        "*512" },
221
222    { 0,        NULL    }
223 };
224
225 /* Translate function to string - CIP General Status codes */
226 static const value_string cip_gs_vals[] = {
227         { CI_GRC_SUCCESS,             "Success" },
228    { CI_GRC_FAILURE,             "Connection failure" },
229    { CI_GRC_NO_RESOURCE,         "Resource unavailable" },
230    { CI_GRC_BAD_DATA,            "Invalid parameter value" },
231    { CI_GRC_BAD_PATH,            "Path segment error" },
232    { CI_GRC_BAD_CLASS_INSTANCE,  "Path destination unknown" },
233    { CI_GRC_PARTIAL_DATA,        "Partial transfer" },
234    { CI_GRC_CONN_LOST,           "Connection lost" },
235    { CI_GRC_BAD_SERVICE,         "Service not supported" },
236    { CI_GRC_BAD_ATTR_DATA,       "Invalid attribute value" },
237    { CI_GRC_ATTR_LIST_ERROR,     "Attribute list error" },
238    { CI_GRC_ALREADY_IN_MODE,     "Already in requested mode/state" },
239    { CI_GRC_BAD_OBJ_MODE,        "Object state conflict" },
240    { CI_GRC_OBJ_ALREADY_EXISTS,  "Object already exists" },
241    { CI_GRC_ATTR_NOT_SETTABLE,   "Attribute not settable" },
242    { CI_GRC_PERMISSION_DENIED,   "Privilege violation" },
243    { CI_GRC_DEV_IN_WRONG_STATE,  "Device state conflict" },
244    { CI_GRC_REPLY_DATA_TOO_LARGE,"Reply data too large" },
245    { CI_GRC_FRAGMENT_PRIMITIVE,  "Fragmentation of a primitive value" },
246    { CI_GRC_CONFIG_TOO_SMALL,    "Not enough data" },
247    { CI_GRC_UNDEFINED_ATTR,      "Attribute not supported" },
248    { CI_GRC_CONFIG_TOO_BIG,      "Too much data" },
249    { CI_GRC_OBJ_DOES_NOT_EXIST,  "Object does not exist" },
250    { CI_GRC_NO_FRAGMENTATION,    "Service fragmentation sequence not in progress" },
251    { CI_GRC_DATA_NOT_SAVED,      "No stored attribute data" },
252    { CI_GRC_DATA_WRITE_FAILURE,  "Store operation failure" },
253    { CI_GRC_REQUEST_TOO_LARGE,   "Routing failure, request packet too large" },
254    { CI_GRC_RESPONSE_TOO_LARGE,  "Routing failure, response packet too large" },
255    { CI_GRC_MISSING_LIST_DATA,   "Missing attribute list entry data" },
256    { CI_GRC_INVALID_LIST_STATUS, "Invalid attribute value list" },
257    { CI_GRC_SERVICE_ERROR,       "Embedded service error" },
258    { CI_GRC_CONN_RELATED_FAILURE,"Vendor specific error" },
259    { CI_GRC_INVALID_PARAMETER,   "Invalid parameter" },
260    { CI_GRC_WRITE_ONCE_FAILURE,  "Write-once value or medium already written" },
261    { CI_GRC_INVALID_REPLY,       "Invalid Reply Received" },
262    { CI_GRC_BAD_KEY_IN_PATH,     "Key Failure in path" },
263    { CI_GRC_BAD_PATH_SIZE,       "Path Size Invalid" },
264    { CI_GRC_UNEXPECTED_ATTR,     "Unexpected attribute in list" },
265    { CI_GRC_INVALID_MEMBER,      "Invalid Member ID" },
266    { CI_GRC_MEMBER_NOT_SETTABLE, "Member not settable" },
267
268         { 0,                                           NULL }
269 };
270
271 /* Translate Vendor ID:s */
272 const value_string cip_vendor_vals[] = {
273    VENDOR_ID_LIST
274
275         { 0, NULL }
276 };
277
278 /* Translate Device Profile:s */
279 const value_string cip_devtype_vals[] = {
280    { DP_GEN_DEV,              "Generic Device"              },
281    { DP_AC_DRIVE,             "AC Drive"                    },
282    { DP_MOTOR_OVERLOAD,       "Motor Overload"              },
283    { DP_LIMIT_SWITCH,         "Limit Switch"                },
284    { DP_IND_PROX_SWITCH,      "Inductive Proximity Switch"  },
285    { DP_PHOTO_SENSOR,         "Photoelectric Sensor"        },
286    { DP_GENP_DISC_IO,         "General Purpose Dicrete I/O" },
287    { DP_RESOLVER,             "Resolver"                    },
288    { DP_COM_ADAPTER,          "Communications Adapter"      },
289    { DP_POS_CNT,              "Position Controller",        },
290    { DP_DC_DRIVE,             "DC Drive"                    },
291    { DP_CONTACTOR,            "Contactor",                  },
292    { DP_MOTOR_STARTER,        "Motor Starter",              },
293    { DP_SOFT_START,           "Soft Start",                 },
294    { DP_HMI,                  "Human-Machine Interface"     },
295    { DP_MASS_FLOW_CNT,        "Mass Flow Controller"        },
296    { DP_PNEUM_VALVE,          "Pneumatic Valve"             },
297    { DP_VACUUM_PRES_GAUGE,    "Vaccuum Pressure Gauge"      },
298
299    { 0, NULL }
300 };
301
302 /* Translate class names */
303 static const value_string cip_class_names_vals[] = {
304         { 0x01,     "Identity Object"                       },
305         { 0x02,     "Message Router"                        },
306         { 0x03,     "DeviceNet Object"                      },
307         { 0x04,     "Assembly Object"                       },
308         { 0x05,     "Connection Object"                     },
309         { 0x06,     "Connection Manager"                    },
310         { 0x07,     "Register Object"                       },
311         { 0x08,     "Discrete Input Point Object"           },
312         { 0x09,     "Discrete Output Point Object"          },
313         { 0x0A,     "Analog Input Point Object"             },
314         { 0x0B,     "Analog Output Point Object"            },
315         { 0x0E,     "Presence Sensing Object"               },
316         { 0x0F,     "Parameter Object"                      },
317         { 0x10,     "Parameter Group Object"                },
318         { 0x12,     "Group Object"                          },
319         { 0x1D,     "Discrete Input Group Object"           },
320         { 0x1E,     "Discrete Output Group Object"          },
321         { 0x1F,     "Discrete Group Object"                 },
322         { 0x20,     "Analog Input Group Object"             },
323         { 0x21,     "Analog Output Group Object"            },
324         { 0x22,     "Analog Group Object"                   },
325         { 0x23,     "Position Sensor Object"                },
326         { 0x24,     "Position Controller Supervisor Object" },
327         { 0x25,     "Position Controller Object"            },
328         { 0x26,     "Block Sequencer Object"                },
329         { 0x27,     "Command Block Object"                  },
330         { 0x28,     "Motor Data Object"                     },
331         { 0x29,     "Control Supervisor Object"             },
332         { 0x2A,     "AC/DC Drive Object"                    },
333         { 0x2B,     "Acknowledge Handler Object"            },
334         { 0x2C,     "Overload Object"                       },
335         { 0x2D,     "Softstart Object"                      },
336         { 0x2E,     "Selection Object"                      },
337         { 0x30,     "S-Device Supervisor Object"            },
338         { 0x31,     "S-Analog Sensor Object"                },
339         { 0x32,     "S-Analog Actuator Object"              },
340         { 0x33,     "S-Single Stage Controller Object"      },
341         { 0x34,     "S-Gas Calibration Object"              },
342         { 0x35,     "Trip Point Object"                     },
343         { 0x37,     "File Object"                           },
344         { 0x38,     "S-Partial Pressure Object"             },
345         { 0xF0,     "ControlNet Object"                     },
346         { 0xF1,     "ControlNet Keeper Object"              },
347         { 0xF2,     "ControlNet Scheduling Object"          },
348         { 0xF3,     "Connection Configuration Object"       },
349         { 0xF4,     "Port Object"                           },
350         { 0xF5,     "TCP/IP Interface Object"               },
351         { 0xF6,     "EtherNet Link Object"                  },
352
353         { 0,                    NULL                                    }
354 };
355
356
357 static proto_item*
358 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
359 {
360   const guint8 *tmp;
361   char         *tmp2, *tmp2start;
362   proto_item   *pi;
363   int           i,tmp_length,tmp2_length;
364   guint32       octet;
365   /* At least one version of Apple's C compiler/linker is buggy, causing
366      a complaint from the linker about the "literal C string section"
367      not ending with '\0' if we initialize a 16-element "char" array with
368      a 16-character string, the fact that initializing such an array with
369      such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
370      '\0' byte in the string nonwithstanding. */
371   static const char my_hex_digits[16] =
372       { '0', '1', '2', '3', '4', '5', '6', '7',
373         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
374
375
376    if( ( length * 2 ) > 32 )
377    {
378       tmp_length = 16;
379       tmp2_length = 36;
380    }
381    else
382    {
383       tmp_length = length;
384       tmp2_length = ( length * 2 ) + 1;
385    }
386
387    tmp = tvb_get_ptr( tvb, start, tmp_length );
388    tmp2 = (char*)g_malloc( tmp2_length );
389
390    tmp2start = tmp2;
391
392    for( i = 0; i < tmp_length; i++ )
393    {
394       octet = tmp[i];
395       octet >>= 4;
396       *tmp2++ = my_hex_digits[octet&0xF];
397       octet = tmp[i];
398       *tmp2++ = my_hex_digits[octet&0xF];
399    }
400
401    if( tmp_length != length )
402    {
403       *tmp2++ = '.';
404       *tmp2++ = '.';
405       *tmp2++ = '.';
406    }
407
408    *tmp2 = 0;
409
410    pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
411
412    g_free( tmp2start );
413
414    return( pi );
415
416 } /* end of add_byte_array_text_to_proto_tree() */
417
418
419 /* Dissect EPATH */
420 static void
421 dissect_epath( tvbuff_t *tvb, proto_item *epath_item, int offset, int path_length )
422 {
423    int pathpos, temp_data, temp_data2, seg_size, i, temp_word;
424    unsigned char segment_type, opt_link_size;
425    proto_tree *path_tree, *port_tree, *net_tree;
426    proto_item *qi, *cia_item, *ds_item;
427    proto_tree *e_key_tree, *cia_tree, *ds_tree;
428    proto_item *mcpi, *port_item, *net_item;
429    proto_tree *mc_tree;
430
431    /* Create a sub tree for the epath */
432    path_tree = proto_item_add_subtree( epath_item, ett_path );
433
434    proto_tree_add_item_hidden(path_tree, hf_cip_epath,
435                                                            tvb, offset, path_length, TRUE );
436
437    pathpos = 0;
438
439    while( pathpos < path_length )
440    {
441       /* Get segement type */
442       segment_type = tvb_get_guint8( tvb, offset + pathpos );
443
444       /* Determine the segment type */
445
446       switch( segment_type & CI_SEGMENT_TYPE_MASK )
447       {
448       case CI_PORT_SEGMENT:
449
450          port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
451          port_tree = proto_item_add_subtree( port_item, ett_port_path );
452
453          /* Add port number */
454          proto_tree_add_item( port_tree, hf_cip_port, tvb, offset + pathpos, 1, TRUE );
455          proto_item_append_text( epath_item, "Port: %d", ( segment_type & 0x0F ) );
456          proto_item_append_text( port_item, ": Port: %d", ( segment_type & 0x0F ) );
457
458          if( segment_type & 0x10 )
459          {
460             /* Add Extended Link Address flag */
461             proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: TRUE" );
462
463             /* Add size of extended link address */
464             opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
465             proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size  );
466
467             /* Add extended link address */
468             proto_tree_add_item( port_tree, hf_cip_link_address_string, tvb, offset+pathpos+2, opt_link_size, FALSE );
469             proto_item_append_text( epath_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
470             proto_item_append_text( port_item,  ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
471
472             /* Pad byte */
473             if( opt_link_size % 2 )
474             {
475               proto_item_set_len( port_item, 3 + opt_link_size );
476               pathpos = pathpos + 3 + opt_link_size;
477             }
478             else
479             {
480               proto_item_set_len( port_item, 2 + opt_link_size );
481               pathpos = pathpos + 2 + opt_link_size;
482             }
483          }
484          else
485          {
486             /* Add Extended Link Address flag */
487             proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: FALSE" );
488
489             /* Add Link Address */
490             proto_tree_add_item( port_tree, hf_cip_link_address_byte, tvb, offset+pathpos+1, 1, FALSE );
491             proto_item_append_text( epath_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
492             proto_item_append_text( port_item,  ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
493
494             proto_item_set_len( port_item, 2 );
495             pathpos += 2;
496          }
497
498          break;
499
500       case CI_LOGICAL_SEGMENT:
501
502          /* Logical segment, determin the logical type */
503
504          switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
505          {
506          case CI_LOGICAL_SEG_CLASS_ID:
507
508             /* Logical Class ID, do a format check */
509
510                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
511                    {
512                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
513                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Class Segment (0x%02X)", segment_type );
514
515                /* Create a sub tree for the class */
516                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
517
518                /* Display the 8-bit class number */
519                proto_tree_add_item( cia_tree, hf_cip_class8, tvb, offset + pathpos + 1, 1, TRUE );
520                proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%02X" ) );
521
522                /* 2 bytes of path used */
523                pathpos += 2;
524             }
525             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
526             {
527                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
528                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Class Segment (0x%02X)", segment_type );
529
530                /* Create a sub tree for the class */
531                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
532
533                /* Display the 16-bit class number */
534                proto_tree_add_item( cia_tree, hf_cip_class16, tvb, offset + pathpos + 2, 2, TRUE );
535                proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%04X" ) );
536
537                /* 4 bytes of path used */
538                pathpos += 4;
539             }
540             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
541             {
542                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
543                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
544
545                /* Create a sub tree for the class */
546                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
547
548                /* Display the 32-bit class number */
549                proto_tree_add_item( cia_tree, hf_cip_class32, tvb, offset + pathpos + 2, 4, TRUE );
550                proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%08X" ) );
551
552                /* 6 bytes of path used */
553                pathpos += 6;
554             }
555             else
556             {
557                /* Unsupported logical segment format */
558                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
559                return;
560             }
561             break;
562
563
564          case CI_LOGICAL_SEG_INST_ID:
565
566             /* Logical Instance ID, do a format check */
567
568                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
569                    {
570                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
571                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
572
573                /* Create a sub tree for the instance */
574                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
575
576                /* Display the 8-bit instance number */
577                proto_tree_add_item( cia_tree, hf_cip_instance8, tvb, offset + pathpos + 1, 1, TRUE );
578                proto_item_append_text( epath_item, "Instance: 0x%02X", temp_data );
579
580                /* 2 bytes of path used */
581                pathpos += 2;
582             }
583             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
584             {
585                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
586                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
587
588                /* Create a sub tree for the instance */
589                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
590
591                /* Display the 16-bit instance number */
592                proto_tree_add_item( cia_tree, hf_cip_instance16, tvb, offset + pathpos + 2, 2, TRUE );
593                proto_item_append_text( epath_item, "Instance: 0x%04X", temp_data );
594
595                /* 4 bytes of path used */
596                pathpos += 4;
597             }
598             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
599             {
600                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
601                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
602
603                /* Create a sub tree for the instance */
604                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
605
606                /* Display the 32-bit instance number */
607                proto_tree_add_item( cia_tree, hf_cip_instance32, tvb, offset + pathpos + 2, 4, TRUE );
608                proto_item_append_text( epath_item, "Instance: 0x%08X", temp_data );
609
610
611                /* 6 bytes of path used */
612                pathpos += 6;
613             }
614             else
615             {
616                /* Unsupported logical segment format */
617                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
618                return;
619             }
620             break;
621
622
623          case CI_LOGICAL_SEG_ATTR_ID:
624
625             /* Logical Attribute ID, do a format check */
626
627                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
628                    {
629                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
630                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
631
632                /* Create a sub tree for the attribute */
633                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
634
635                /* Display the 8-bit attribute number */
636                proto_tree_add_item( cia_tree, hf_cip_attribute8, tvb, offset + pathpos + 1, 1, TRUE );
637                proto_item_append_text( epath_item, "Attribute: 0x%02X", temp_data );
638
639                /* 2 bytes of path used */
640                pathpos += 2;
641             }
642             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
643             {
644                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
645                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
646
647                /* Create a sub tree for the attribute */
648                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
649
650                /* Display the 16-bit attribute number */
651                proto_tree_add_item( cia_tree, hf_cip_attribute16, tvb, offset + pathpos + 2, 2, TRUE );
652                proto_item_append_text( epath_item, "Attribute: 0x%04X", temp_data );
653
654                /* 4 bytes of path used */
655                pathpos += 4;
656             }
657             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
658             {
659                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
660                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
661
662                /* Create a sub tree for the attribute */
663                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
664
665                /* Display the 32-bit attribute number */
666                proto_tree_add_item( cia_tree, hf_cip_attribute32, tvb, offset + pathpos + 2, 4, TRUE );
667                proto_item_append_text( epath_item, "Attribute: 0x%08X", temp_data );
668
669                /* 6 bytes of path used */
670                pathpos += 6;
671             }
672             else
673             {
674                /* Unsupported logical segment format */
675                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
676                return;
677             }
678             break;
679
680
681          case CI_LOGICAL_SEG_CON_POINT:
682
683             /* Logical Connection point , do a format check */
684
685                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
686                    {
687                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
688                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Connection Point Segment (0x%02X)", segment_type );
689
690                /* Create a sub tree for the connection point */
691                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
692
693                /* Display the 8-bit connection point number */
694                proto_tree_add_item( cia_tree, hf_cip_conpoint8, tvb, offset + pathpos + 1, 1, TRUE );
695                proto_item_append_text( epath_item, "Connection Point: 0x%02X", temp_data );
696
697                /* 2 bytes of path used */
698                pathpos += 2;
699             }
700             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
701             {
702                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
703                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 4, "16-Bit Logical Connection Point Segment (0x%02X)", segment_type );
704
705                /* Create a sub tree for the connection point */
706                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
707
708                /* Display the 16-bit connection point number */
709                proto_tree_add_item( cia_tree, hf_cip_conpoint16, tvb, offset + pathpos + 2, 2, TRUE );
710                proto_item_append_text( epath_item, "Connection Point: 0x%04X", temp_data );
711
712                /* 4 bytes of path used */
713                pathpos += 4;
714             }
715             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
716             {
717                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
718                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 6, "32-Bit Logical Connection Point Segment (0x%02X)", segment_type );
719
720                /* Create a sub tree for the connection point */
721                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
722
723                /* Display the 32-bit connection point number */
724                proto_tree_add_item( cia_tree, hf_cip_conpoint32, tvb, offset + pathpos + 2, 4, TRUE );
725                proto_item_append_text( epath_item, "Connection Point: 0x%08X", temp_data );
726
727                /* 6 bytes of path used */
728                pathpos += 6;
729             }
730             else
731             {
732                /* Unsupported logical segment format */
733                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
734                return;
735             }
736             break;
737
738
739          case CI_LOGICAL_SEG_SPECIAL:
740
741             /* Logical Special ID, the only logical format sepcifyed is electronic key */
742
743             if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
744             {
745                /* Get the Key Format */
746                temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
747
748                if( temp_data == CI_E_KEY_FORMAT_VAL )
749                {
750                   qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
751
752                   /* Create a sub tree for the IOI */
753                   e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
754
755                   /* Print the key type */
756                   proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
757
758                   /* Get the Vendor ID */
759                       temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
760                   proto_tree_add_item( e_key_tree, hf_cip_vendor, tvb, offset + pathpos + 2, 2, TRUE);
761                   proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
762
763                   /* Get Device Type */
764                          temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
765                          proto_tree_add_item( e_key_tree, hf_cip_devtype, tvb, offset + pathpos + 4, 2, TRUE);
766                   proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
767
768                   /* Product Code */
769                          temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
770                   proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
771
772                   /* Major revision/Compatibility */
773                          temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
774
775                                         /* Add Major revision/Compatibility tree */
776                                         mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
777                                         mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
778
779                                         /* Add Compatibility bit info */
780                   proto_tree_add_item(mc_tree, hf_cip_fwo_comp,
781                                                         tvb, offset + pathpos + 8, 1, TRUE );
782
783                   proto_item_append_text( mcpi, "%s, Major Revision: %d",
784                               val_to_str( ( temp_data & 0x80 )>>7, cip_com_bit_vals , "" ),
785                               temp_data & 0x7F );
786
787                                         /* Major revision */
788                                         proto_tree_add_item(mc_tree, hf_cip_fwo_mrev,
789                                                         tvb, offset + pathpos + 8, 1, TRUE );
790
791                   /* Minor revision */
792                   temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
793                   proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
794
795                   proto_item_append_text( qi, ", %d.%d", ( temp_data & 0x7F ), temp_data2 );
796
797                   proto_item_append_text(epath_item, "[Key]" );
798
799                   /* Increment the path pointer */
800                   pathpos += 10;
801                }
802                else
803                {
804                   /* Unsupported electronic key format */
805                   proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
806                   return;
807                }
808             }
809             else
810             {
811                /* Unsupported special segment format */
812                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
813                return;
814             }
815             break;
816
817          default:
818
819             /* Unsupported logical segment type */
820             proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
821             return;
822
823          } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
824          break;
825
826
827       case CI_DATA_SEGMENT:
828
829          /* Data segment, determin the logical type */
830
831          switch( segment_type )
832          {
833             case CI_DATA_SEG_SIMPLE:
834
835                /* Simple data segment */
836                ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
837
838                /* Create a sub tree */
839                ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
840
841                /* Segment size */
842                seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
843                proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
844
845                /* Segment data  */
846                if( seg_size != 0 )
847                {
848                   qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
849
850                   for( i=0; i < seg_size/2; i ++ )
851                   {
852                     temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
853                     proto_item_append_text(qi, " 0x%04X", temp_word );
854                   }
855
856                   proto_item_set_len(qi, seg_size);
857                }
858
859                proto_item_set_len( ds_item, 2 + seg_size );
860                pathpos = pathpos + 2 + seg_size;
861
862                proto_item_append_text(epath_item, "[Data]" );
863
864                break;
865
866             case CI_DATA_SEG_SYMBOL:
867
868                /* ANSI extended symbol segment */
869                ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
870
871                /* Create a sub tree */
872                ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
873
874                /* Segment size */
875                seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
876                proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
877
878                /* Segment data  */
879                if( seg_size != 0 )
880                {
881                   qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2, seg_size, "Data: %s",
882                         tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
883
884                   proto_item_append_text(epath_item, "%s", tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
885                   proto_tree_add_item_hidden( ds_tree, hf_cip_symbol, tvb, offset + pathpos + 2, seg_size, FALSE );
886
887                   if( seg_size %2 )
888                   {
889                      /* We have a PAD BYTE */
890                      proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2 + seg_size, 1, "Pad Byte (0x%02X)",
891                          tvb_get_guint8( tvb, offset + pathpos + 2 + seg_size ) );
892                      pathpos++;
893                      seg_size++;
894                   }
895                }
896
897                proto_item_set_len( ds_item, 2 + seg_size );
898                pathpos = pathpos + 2 + seg_size;
899
900                break;
901
902             default:
903                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
904                return;
905
906             } /* End of switch sub-type */
907
908             break;
909
910       case CI_NETWORK_SEGMENT:
911
912          /* Network segment -Determine the segment sub-type */
913
914          switch( segment_type & CI_NETWORK_SEG_TYPE_MASK )
915          {
916            case CI_NETWORK_SEG_SCHEDULE:
917                net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Schedule" );
918                net_tree = proto_item_add_subtree( net_item, ett_port_path );
919
920                proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Multiplier/Phase: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
921
922                /* 2 bytes of path used */
923                pathpos += 2;
924                break;
925
926             case CI_NETWORK_SEG_FIXED_TAG:
927                net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Fixed Tag" );
928                net_tree = proto_item_add_subtree( net_item, ett_port_path );
929
930                proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Fixed Tag: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
931
932                /* 2 bytes of path used */
933                pathpos += 2;
934                break;
935
936             case CI_NETWORK_SEG_PROD_INHI:
937                net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Production Inhibit" );
938                net_tree = proto_item_add_subtree( net_item, ett_port_path );
939
940                proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Production Inhibit Time: %dms", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
941
942                /* 2 bytes of path used */
943                pathpos += 2;
944                break;
945
946             default:
947                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
948                return;
949
950             } /* End of switch sub-type */
951
952       break;
953
954      default:
955
956          /* Unsupported segment type */
957          proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
958          return;
959
960       } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
961
962       /* Next path segment */
963       if( pathpos < path_length )
964          proto_item_append_text( epath_item, ", " );
965
966    } /* end of while( pathpos < path_length ) */
967
968 } /* end of dissect_epath() */
969
970
971 static void
972 dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
973 {
974    proto_item *pi, *rrsc_item, *ncppi, *ar_item, *temp_item, *temp_item2, *status_item;
975         proto_tree *temp_tree, *rrsc_tree, *ncp_tree, *cmd_data_tree, *status_tree;
976         int req_path_size, conn_path_size, temp_data;
977         unsigned char gen_status;
978    unsigned char add_stat_size;
979    unsigned char temp_byte, route_path_size;
980    unsigned char app_rep_size, i;
981    int msg_req_siz, num_services, serv_offset;
982
983
984    /* Add Service code & Request/Response tree */
985         rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
986         rrsc_tree = proto_item_add_subtree( rrsc_item, ett_rrsc );
987
988         /* Add Request/Response */
989    proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
990
991    proto_item_append_text( rrsc_item, "%s (%s)",
992                val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
993                   cip_sc_vals , "Unknown Service (%x)"),
994                val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
995                   cip_sc_rr, "") );
996
997         /* Add Service code */
998         proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
999
1000         if( tvb_get_guint8( tvb, offset ) & 0x80 )
1001         {
1002            /* Response message */
1003            status_item = proto_tree_add_text( item_tree, tvb, offset+2, 1, "Status: " );
1004            status_tree = proto_item_add_subtree( status_item, ett_status_item );
1005
1006                 /* Add general status */
1007                 gen_status = tvb_get_guint8( tvb, offset+2 );
1008                 proto_tree_add_item(status_tree, hf_cip_genstat, tvb, offset+2, 1, TRUE );
1009                 proto_item_append_text( status_item, "%s", val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
1010                      cip_gs_vals , "Unknown Response (%x)")   );
1011
1012       /* Add reply status to info column */
1013       if(check_col(pinfo->cinfo, COL_INFO))
1014       {
1015          col_append_fstr( pinfo->cinfo, COL_INFO, "%s",
1016                   val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
1017                      cip_gs_vals , "Unknown Response (%x)") );
1018       }
1019
1020       /* Add additional status size */
1021       proto_tree_add_text( status_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)",
1022          tvb_get_guint8( tvb, offset+3 ) );
1023
1024                 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
1025
1026                 if( add_stat_size )
1027                 {
1028          proto_item_append_text( status_item, ", Extended:" );
1029
1030          /* Add additional status */
1031          pi = proto_tree_add_text( status_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
1032
1033          for( i=0; i < add_stat_size/2; i ++ )
1034          {
1035            proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
1036            proto_item_append_text( status_item, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
1037          }
1038                 }
1039
1040                 proto_item_set_len( status_item, 2 + add_stat_size );
1041
1042       /* If there is any command specific data create a sub-tree for it */
1043       if( ( item_length-4-add_stat_size ) != 0 )
1044       {
1045          pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific data" );
1046          cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1047
1048                    if( gen_status == CI_GRC_SUCCESS )
1049                 {
1050                         /* Success responses */
1051
1052                         if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN )
1053             {
1054                /* Forward open Response (Success) */
1055
1056                /* Display originator to target connection ID */
1057                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size );
1058                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1059
1060                /* Display target to originator connection ID */
1061                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1062                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1063
1064                /* Display connection serial number */
1065                temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
1066                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", temp_data );
1067
1068                /* Display the originator vendor id */
1069                proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+10, 2, TRUE);
1070
1071                /* Display the originator serial number */
1072                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
1073                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", temp_data );
1074
1075                /* Display originator to target actual packet interval */
1076                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
1077                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 );
1078
1079                /* Display originator to target actual packet interval */
1080                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
1081                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 );
1082
1083                /* Display the application reply size */
1084                app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
1085                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1086
1087                /* Display the Reserved byte */
1088                temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
1089                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
1090
1091                if( app_rep_size != 0 )
1092                {
1093                   /* Display application Reply data */
1094                   ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
1095
1096                   for( i=0; i < app_rep_size; i++ )
1097                   {
1098                     temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
1099                     proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1100                   }
1101
1102                 } /* End of if reply data */
1103
1104             } /* End of if forward open response */
1105                         else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE )
1106             {
1107                /* Forward close response (Success) */
1108
1109                /* Display connection serial number */
1110                temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1111                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1112
1113                /* Display the originator vendor id */
1114                proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
1115
1116                /* Display the originator serial number */
1117                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1118                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1119
1120                /* Display the application reply size */
1121                app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
1122                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1123
1124                /* Display the Reserved byte */
1125                temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1126                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
1127
1128                if( app_rep_size != 0 )
1129                {
1130                   /* Display application Reply data */
1131                   ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
1132
1133                   for( i=0; i < app_rep_size; i ++ )
1134                   {
1135                     temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
1136                     proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1137                   }
1138
1139                 } /* End of if reply data */
1140
1141             } /* End of if forward close response */
1142             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1143             {
1144                /* Unconnected send response (Success) */
1145
1146                /* Display service response data */
1147                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1148             }
1149             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
1150             {
1151                /* Multiple Service Reply (Success)*/
1152
1153                /* Add number of replies */
1154                num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
1155                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
1156
1157                /* Add replies */
1158                temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
1159
1160                for( i=0; i < num_services; i++ )
1161                {
1162                   int serv_length;
1163
1164                   serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
1165
1166                   if( i == (num_services-1) )
1167                   {
1168                      /* Last service to add */
1169                      proto_item_append_text(temp_item, "%d", serv_offset );
1170                      serv_length = item_length-add_stat_size-serv_offset-4;
1171                   }
1172                   else
1173                   {
1174                      proto_item_append_text(temp_item, "%d, ", serv_offset );
1175                      serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
1176                   }
1177
1178                   temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
1179                   temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1180
1181                   /*
1182                   ** We call our selves again to disect embedded packet
1183                   */
1184
1185                   if(check_col(pinfo->cinfo, COL_INFO))
1186                      col_append_fstr( pinfo->cinfo, COL_INFO, ", ");
1187
1188                   dissect_cip_data( temp_tree, tvb, offset+serv_offset+4, serv_length, pinfo );
1189                }
1190             } /* End if Multiple service Packet */
1191             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
1192             {
1193                /* Get Attribute List Reply (Success)*/
1194
1195                int att_count;
1196
1197                /* Add Attribute Count */
1198                att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
1199                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
1200
1201                /* Add the data */
1202                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
1203
1204             } /* End if Multiple service Packet */
1205             else
1206                         {
1207                            /* Add data */
1208                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1209                    } /* end of check service code */
1210
1211            }
1212          else
1213          {
1214             /* Error responses */
1215
1216             if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN ) ||
1217                 ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE ) )
1218             {
1219                /* Forward open and forward close error response look the same */
1220
1221                /* Display connection serial number */
1222                temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1223                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1224
1225                /* Display the originator vendor id */
1226                proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+4+add_stat_size+2, 2, TRUE);
1227
1228                /* Display the originator serial number */
1229                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1230                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1231
1232                /* Display remaining path size */
1233                temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
1234                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
1235
1236                /* Display reserved data */
1237                temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1238                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
1239             }
1240             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1241             {
1242                /* Unconnected send response (Unsuccess) */
1243
1244                /* Display remaining path size */
1245                temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
1246                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
1247             }
1248             else
1249             {
1250                /* Add data */
1251                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1252             }
1253
1254          } /* end of if-else( CI_CRC_SUCCESS ) */
1255
1256       } /* End of if command-specific data present */
1257
1258         } /* End of if reply */
1259         else
1260         {
1261            /* Request message */
1262
1263       /* Add service to info column */
1264       if(check_col(pinfo->cinfo, COL_INFO))
1265       {
1266          col_append_fstr( pinfo->cinfo, COL_INFO, "%s",
1267                   val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1268                      cip_sc_vals , "Unknown Service (%x)") );
1269       }
1270
1271            /* Add path size to tree */
1272            req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
1273            proto_tree_add_text( item_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
1274
1275       /* Add the epath */
1276       pi = proto_tree_add_text(item_tree, tvb, offset+2, req_path_size, "Request Path: ");
1277       dissect_epath( tvb, pi, offset+2, req_path_size );
1278
1279       /* If there is any command specific data creat a sub-tree for it */
1280       if( (item_length-req_path_size-2) != 0 )
1281       {
1282
1283          pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
1284          cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1285
1286          /* Check what service code that recived */
1287
1288          if( tvb_get_guint8( tvb, offset ) == SC_FWD_OPEN )
1289          {
1290             /* Forward open Request*/
1291
1292             /* Display the priority/tick timer */
1293             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1294             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1295
1296             /* Display the time-out ticks */
1297             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1298             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1299
1300             /* Display the actual time out */
1301             temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1302             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1303
1304             /* Display originator to taget connection ID */
1305             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
1306             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1307
1308             /* Display target to originator connection ID */
1309             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1310             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1311
1312             /* Display connection serial number */
1313             temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
1314             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
1315
1316             /* Display the originator vendor id */
1317             proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+12, 2, TRUE);
1318
1319             /* Display the originator serial number */
1320             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
1321             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
1322
1323             /* Display the timeout multiplier */
1324             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
1325             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 );
1326
1327             /* Put out an indicator for the reserved bytes */
1328             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
1329
1330             /* Display originator to target requested packet interval */
1331             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
1332             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 );
1333
1334               /* Display originator to target network connection patameterts, in a tree */
1335               temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
1336               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 );
1337               ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1338
1339             /* Add the data to the tree */
1340             proto_tree_add_item(ncp_tree, hf_cip_fwo_own,
1341                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1342                         proto_tree_add_item(ncp_tree, hf_cip_fwo_typ,
1343                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1344             proto_tree_add_item(ncp_tree, hf_cip_fwo_prio,
1345                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1346                         proto_tree_add_item(ncp_tree, hf_cip_fwo_fixed_var,
1347                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1348                         proto_tree_add_item(ncp_tree, hf_cip_fwo_con_size,
1349                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1350
1351             /* Display target to originator requested packet interval */
1352             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
1353             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 );
1354
1355               /* Display target to originator network connection patameterts, in a tree */
1356               temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
1357               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 );
1358               ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1359
1360             /* Add the data to the tree */
1361             proto_tree_add_item(ncp_tree, hf_cip_fwo_own,
1362                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1363                         proto_tree_add_item(ncp_tree, hf_cip_fwo_typ,
1364                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1365             proto_tree_add_item(ncp_tree, hf_cip_fwo_prio,
1366                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1367                         proto_tree_add_item(ncp_tree, hf_cip_fwo_fixed_var,
1368                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1369                         proto_tree_add_item(ncp_tree, hf_cip_fwo_con_size,
1370                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1371
1372             /* Transport type/trigger in tree*/
1373             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
1374
1375               ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
1376               ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1377
1378             /* Add the data to the tree */
1379             proto_tree_add_item(ncp_tree, hf_cip_fwo_dir,
1380                                         tvb, offset+2+req_path_size+34, 1, TRUE );
1381
1382                         proto_tree_add_item(ncp_tree, hf_cip_fwo_trigg,
1383                                         tvb, offset+2+req_path_size+34, 1, TRUE );
1384
1385             proto_tree_add_item(ncp_tree, hf_cip_fwo_class,
1386                                         tvb, offset+2+req_path_size+34, 1, TRUE );
1387
1388             /* Add path size */
1389             conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
1390             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1391
1392             /* Add the epath */
1393             pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
1394             dissect_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size );
1395          }
1396          else if( tvb_get_guint8( tvb, offset ) == SC_FWD_CLOSE )
1397          {
1398             /* Forward Close Request */
1399
1400             /* Display the priority/tick timer */
1401             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1402             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1403
1404             /* Display the time-out ticks */
1405             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1406             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1407
1408             /* Display the actual time out */
1409             temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1410             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1411
1412             /* Display connection serial number */
1413             temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1414             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
1415
1416             /* Display the originator vendor id */
1417             proto_tree_add_item( cmd_data_tree, hf_cip_vendor, tvb, offset+2+req_path_size+4, 2, TRUE);
1418
1419             /* Display the originator serial number */
1420             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1421             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
1422
1423             /* Add the path size */
1424             conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
1425             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1426
1427             /* Add the reserved byte */
1428             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
1429             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
1430
1431             /* Add the EPATH */
1432             pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
1433             dissect_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size );
1434
1435          } /* End of forward close */
1436          else if( tvb_get_guint8( tvb, offset ) == SC_UNCON_SEND )
1437          {
1438             /* Unconnected send */
1439
1440             /* Display the priority/tick timer */
1441             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1442             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1443
1444             /* Display the time-out ticks */
1445             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1446             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1447
1448             /* Display the actual time out */
1449             temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1450             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1451
1452             /* Message request size */
1453             msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1454             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
1455
1456             /* Message Request */
1457             temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
1458             temp_tree = proto_item_add_subtree(temp_item, ett_mes_req );
1459
1460             /*
1461             ** We call our selves again to disect embedded packet
1462             */
1463
1464             if(check_col(pinfo->cinfo, COL_INFO))
1465                col_append_fstr( pinfo->cinfo, COL_INFO, ": ");
1466
1467             dissect_cip_data( temp_tree, tvb, offset+2+req_path_size+4, msg_req_siz, pinfo );
1468
1469             if( msg_req_siz % 2 )
1470             {
1471                /* Pad byte */
1472                proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
1473                   tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
1474                msg_req_siz++;   /* include the padding */
1475             }
1476
1477             /* Route Path Size */
1478             route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
1479             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 );
1480
1481             /* Reserved */
1482             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
1483                 tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
1484
1485             /* Route Path */
1486             temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path: ");
1487             dissect_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size );
1488
1489          } /* End if unconnected send */
1490          else if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
1491          {
1492             /* Multiple service packet */
1493
1494             /* Add number of services */
1495             num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
1496             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
1497
1498             /* Add services */
1499             temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
1500
1501             for( i=0; i < num_services; i++ )
1502             {
1503                int serv_length;
1504
1505                serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
1506
1507                if( i == (num_services-1) )
1508                {
1509                   /* Last service to add */
1510                   serv_length = item_length-2-req_path_size-serv_offset;
1511                   proto_item_append_text(temp_item, "%d", serv_offset );
1512                }
1513                else
1514                {
1515                   serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
1516                   proto_item_append_text(temp_item, "%d, ", serv_offset );
1517                }
1518
1519                temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
1520                temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1521
1522                /*
1523                ** We call our selves again to disect embedded packet
1524                */
1525
1526                if(check_col(pinfo->cinfo, COL_INFO))
1527                   col_append_fstr( pinfo->cinfo, COL_INFO, ", ");
1528
1529                dissect_cip_data( temp_tree, tvb, offset+serv_offset+6, serv_length, pinfo );
1530             }
1531          } /* End if Multiple service Packet */
1532          else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
1533          {
1534             /* Get attribute list request */
1535
1536             int att_count;
1537
1538             /* Add number of services */
1539             att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
1540             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
1541
1542             /* Add Attribute List */
1543             temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
1544
1545             for( i=0; i < att_count; i++ )
1546             {
1547                if( i == (att_count-1) )
1548                   proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1549                else
1550                   proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1551             }
1552
1553          } /* End of Get attribute list request */
1554          else
1555          {
1556                       /* Add data */
1557             add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
1558          } /* End of check service code */
1559
1560       } /* End of if command-specific data present */
1561
1562         } /* End of if-else( request ) */
1563
1564 } /* End of dissect_cip_data() */
1565
1566
1567 static int
1568 dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1569 {
1570    proto_item *ti;
1571    proto_tree *cip_tree;
1572
1573    /* Make entries in Protocol column and Info column on summary display */
1574    if( check_col( pinfo->cinfo, COL_PROTOCOL ) )
1575       col_set_str( pinfo->cinfo, COL_PROTOCOL, "CIP" );
1576
1577    if (check_col( pinfo->cinfo, COL_INFO ) )
1578       col_clear( pinfo->cinfo, COL_INFO );
1579
1580    if( tree )
1581    {
1582       /* Create display subtree for the protocol */
1583       ti = proto_tree_add_item(tree, proto_cip, tvb, 0, -1, FALSE);
1584       cip_tree = proto_item_add_subtree( ti, ett_cip );
1585
1586       dissect_cip_data( cip_tree, tvb, 0, tvb_length(tvb), pinfo );
1587    }
1588
1589    return tvb_length(tvb);
1590 }
1591
1592
1593 void
1594 proto_register_cip(void)
1595 {
1596    /* Setup list of header fields */
1597         static hf_register_info hf[] = {
1598
1599       { &hf_cip_rr,
1600                 { "Request/Response", "cip.rr",
1601                         FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
1602                         "Request or Response message", HFILL }
1603                 },
1604                 { &hf_cip_sc,
1605                         { "Service", "cip.sc",
1606                         FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
1607                         "Service Code", HFILL }
1608                 },
1609                 { &hf_cip_epath,
1610                         { "EPath", "cip.epath",
1611                         FT_BYTES, BASE_HEX, NULL, 0,
1612                         "EPath", HFILL }
1613                 },
1614                 { &hf_cip_genstat,
1615                         { "General Status", "cip.genstat",
1616                         FT_UINT8, BASE_HEX, VALS(cip_gs_vals), 0,
1617                         "General Status", HFILL }
1618                 },
1619                 { &hf_cip_port,
1620                         { "Port", "cip.port",
1621                         FT_UINT8, BASE_DEC, NULL, 0,
1622                         "Port Identifier", HFILL }
1623                 },
1624                 { &hf_cip_link_address_byte,
1625                         { "Link Address", "cip.linkaddress",
1626                         FT_UINT8, BASE_DEC, NULL, 0,
1627                         "Link Address", HFILL }
1628                 },
1629                 { &hf_cip_link_address_string,
1630                         { "Link Address", "cip.linkaddress",
1631                         FT_STRING, BASE_NONE, NULL, 0,
1632                         "Link Address", HFILL }
1633                 },
1634                 { &hf_cip_class8,
1635                         { "Class", "cip.class",
1636                         FT_UINT8, BASE_HEX, VALS(cip_class_names_vals), 0,
1637                         "Class", HFILL }
1638                 },
1639                 { &hf_cip_class16,
1640                         { "Class", "cip.class",
1641                         FT_UINT16, BASE_HEX, VALS(cip_class_names_vals), 0,
1642                         "Class", HFILL }
1643                 },
1644                 { &hf_cip_class32,
1645                         { "Class", "cip.class",
1646                         FT_UINT32, BASE_HEX, VALS(cip_class_names_vals), 0,
1647                         "Class", HFILL }
1648                 },
1649                 { &hf_cip_instance8,
1650                         { "Instance", "cip.instance",
1651                         FT_UINT8, BASE_HEX, NULL, 0,
1652                         "Instance", HFILL }
1653                 },
1654                 { &hf_cip_instance16,
1655                         { "Instance", "cip.instance",
1656                         FT_UINT16, BASE_HEX, NULL, 0,
1657                         "Instance", HFILL }
1658                 },
1659                 { &hf_cip_instance32,
1660                         { "Instance", "cip.instance",
1661                         FT_UINT32, BASE_HEX, NULL, 0,
1662                         "Instance", HFILL }
1663                 },
1664                 { &hf_cip_attribute8,
1665                         { "Attribute", "cip.attribute",
1666                         FT_UINT8, BASE_HEX, NULL, 0,
1667                         "Attribute", HFILL }
1668                 },
1669                 { &hf_cip_attribute16,
1670                         { "Attribute", "cip.attribute",
1671                         FT_UINT16, BASE_HEX, NULL, 0,
1672                         "Attribute", HFILL }
1673                 },
1674                 { &hf_cip_attribute32,
1675                         { "Attribute", "cip.attribute",
1676                         FT_UINT32, BASE_HEX, NULL, 0,
1677                         "Attribute", HFILL }
1678                 },
1679                 { &hf_cip_conpoint8,
1680                         { "Connection Point", "cip.connpoint",
1681                         FT_UINT8, BASE_HEX, NULL, 0,
1682                         "Connection Point", HFILL }
1683                 },
1684                 { &hf_cip_conpoint16,
1685                         { "Connection Point", "cip.connpoint",
1686                         FT_UINT16, BASE_HEX, NULL, 0,
1687                         "Connection Point", HFILL }
1688                 },
1689                 { &hf_cip_conpoint32,
1690                         { "Connection Point", "cip.connpoint",
1691                         FT_UINT16, BASE_HEX, NULL, 0,
1692                         "Connection Point", HFILL }
1693                 },
1694                 { &hf_cip_symbol,
1695                         { "Symbol", "cip.symbol",
1696                         FT_STRING, BASE_NONE, NULL, 0,
1697                         "ANSI Extended Symbol Segment", HFILL }
1698                 },
1699                 { &hf_cip_vendor,
1700                         { "Vendor ID", "cip.vendor",
1701                         FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
1702                         "Vendor ID", HFILL }
1703                 },
1704                 { &hf_cip_devtype,
1705                         { "Device Type", "cip.devtype",
1706                         FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
1707                         "Device Type", HFILL }
1708                 },
1709                 { &hf_cip_fwo_comp,
1710                         { "Compatibility", "cip.fwo.cmp",
1711                         FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80,
1712                         "Fwd Open: Compatibility bit", HFILL }
1713                 },
1714       { &hf_cip_fwo_mrev,
1715                         { "Major Revision", "cip.fwo.major",
1716                         FT_UINT8, BASE_DEC, NULL, 0x7F,
1717                         "Fwd Open: Major Revision", HFILL }
1718                 },
1719       { &hf_cip_fwo_con_size,
1720                         { "Connection Size", "cip.fwo.consize",
1721                         FT_UINT16, BASE_DEC, NULL, 0x01FF,
1722                         "Fwd Open: Connection size", HFILL }
1723                 },
1724       { &hf_cip_fwo_fixed_var,
1725                         { "Connection Size Type", "cip.fwo.f_v",
1726                         FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200,
1727                         "Fwd Open: Fixed or variable connection size", HFILL }
1728                 },
1729       { &hf_cip_fwo_prio,
1730                         { "Priority", "cip.fwo.prio",
1731                         FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00,
1732                         "Fwd Open: Connection priority", HFILL }
1733                 },
1734       { &hf_cip_fwo_typ,
1735                         { "Connection Type", "cip.fwo.type",
1736                         FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000,
1737                         "Fwd Open: Connection type", HFILL }
1738                 },
1739       { &hf_cip_fwo_own,
1740                         { "Owner", "cip.fwo.owner",
1741                         FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000,
1742                         "Fwd Open: Redundant owner bit", HFILL }
1743                 },
1744                 { &hf_cip_fwo_dir,
1745                         { "Direction", "cip.fwo.dir",
1746                         FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), 0x80,
1747                         "Fwd Open: Direction", HFILL }
1748                 },
1749       { &hf_cip_fwo_trigg,
1750                         { "Trigger", "cip.fwo.trigger",
1751                         FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), 0x70,
1752                         "Fwd Open: Production trigger", HFILL }
1753                 },
1754       { &hf_cip_fwo_class,
1755                         { "Class", "cip.fwo.transport",
1756                         FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), 0x0F,
1757                         "Fwd Open: Transport Class", HFILL }
1758                 }
1759    };
1760
1761    /* Setup protocol subtree array */
1762         static gint *ett[] = {
1763                 &ett_cip,
1764                 &ett_path,
1765                 &ett_ekey_path,
1766                 &ett_rrsc,
1767                 &ett_mcsc,
1768                 &ett_ncp,
1769                 &ett_cia_path,
1770                 &ett_data_seg,
1771                 &ett_lsrcf,
1772                 &ett_mes_req,
1773                 &ett_cmd_data,
1774                 &ett_port_path,
1775                 &ett_mult_ser,
1776                 &ett_path,
1777                 &ett_status_item
1778         };
1779
1780    /* Register the protocol name and description */
1781    proto_cip = proto_register_protocol("Common Industrial Protocol",
1782             "CIP", "cip");
1783
1784    /* Required function calls to register the header fields and subtrees used */
1785         proto_register_field_array(proto_cip, hf, array_length(hf));
1786         proto_register_subtree_array(ett, array_length(ett));
1787
1788 } /* end of proto_register_cip() */
1789
1790
1791 void
1792 proto_reg_handoff_cip(void)
1793 {
1794         dissector_handle_t cip_handle;
1795
1796    /* Create dissector handles */
1797    cip_handle = new_create_dissector_handle( dissect_cip, proto_cip );
1798
1799    /* Register for UCMM CIP data, using EtherNet/IP SendRRData service*/
1800         dissector_add( "enip.srrd.iface", ENIP_CIP_INTERFACE, cip_handle );
1801
1802         /* Register for Connected CIP data, using EtherNet/IP SendUnitData service*/
1803         dissector_add( "enip.sud.iface", ENIP_CIP_INTERFACE, cip_handle );
1804
1805 } /* end of proto_reg_handoff_cip() */