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