Maybe the problem is that the compilers used on AIX weren't defining
[obnox/wireshark/wip.git] / packet-enip.c
1 /* packet-enip.c
2  * Routines for EtherNet/IP (Industrial Protocol) dissection
3  * EtherNet/IP Home: www.odva.org
4  *
5  * Copyright 2003
6  * Magnus Hansson <mah@hms.se>
7  * Joakim Wiberg <jow@hms.se>
8  *
9  * $Id: packet-enip.c,v 1.7 2003/10/06 08:10:32 guy Exp $
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 #ifdef NEED_SNPRINTF_H
41 # include "snprintf.h"
42 #endif
43
44 #include <epan/packet.h>
45
46 /* Defines */
47 #define ENIP_ENCAP_PORT         44818   /* EtherNet/IP located on port 44818 */
48 #define ENIP_IO_PORT               2222 /* EtherNet/IP IO located on port 2222  */
49
50 /* return codes of function classifying packets as query/response */
51 #define REQUEST_PACKET     0
52 #define RESPONSE_PACKET         1
53 #define CANNOT_CLASSIFY         2
54
55 /* CIP Encapsulation function codes */
56 #define NOP                0x0000
57 #define LIST_SERVICES      0x0004
58 #define LIST_IDENTITY      0x0063
59 #define LIST_INTERFACES    0x0064
60 #define REGISTER_SESSION   0x0065
61 #define UNREGISTER_SESSION 0x0066
62 #define SEND_RR_DATA       0x006F
63 #define SEND_UNIT_DATA     0x0070
64 #define INDICATE_STATUS    0x0072
65 #define CANCEL             0x0073
66
67 /* CIP Encapsulation status codes */
68 #define SUCCESS               0x0000
69 #define INVALID_CMD           0x0001
70 #define NO_RESOURCES          0x0002
71 #define INCORRECT_DATA        0x0003
72 #define INVALID_SESSION       0x0064
73 #define INVALID_LENGTH        0x0065
74 #define UNSUPPORTED_PROT_REV  0x0069
75
76 /* CIP Common Data Format Type IDs */
77 #define CDF_NULL              0x0000
78 #define LIST_IDENTITY_RESP    0x000C
79 #define CONNECTION_BASED      0x00A1
80 #define CONNECTION_TRANSPORT  0x00B1
81 #define UNCONNECTED_MSG       0x00B2
82 #define LIST_SERVICES_RESP    0x0100
83 #define SOCK_ADR_INFO_OT      0x8000
84 #define SOCK_ADR_INFO_TO      0x8001
85 #define SEQ_ADDRESS           0x8002
86
87 /* CIP Service Codes */
88 #define SC_GET_ATT_ALL           0x01
89 #define SC_SET_ATT_ALL           0x02
90 #define SC_GET_ATT_LIST          0x03
91 #define SC_SET_ATT_LIST          0x04
92 #define SC_RESET                 0x05
93 #define SC_START                 0x06
94 #define SC_STOP                  0x07
95 #define SC_CREATE                0x08
96 #define SC_DELETE                0x09
97 #define SC_MULT_SERV_PACK        0x0A
98 #define SC_APPLY_ATTRIBUTES      0x0D
99 #define SC_GET_ATT_SINGLE        0x0E
100 #define SC_SET_ATT_SINGLE        0x10
101 #define SC_FIND_NEXT_OBJ_INST    0x11
102 #define SC_RESTOR                0x15
103 #define SC_SAVE                  0x16
104 #define SC_NO_OP                 0x17
105 #define SC_GET_MEMBER            0x18
106 #define SC_SET_MEMBER            0x19
107
108 #define SC_FWD_CLOSE             0x4E
109 #define SC_UNCON_SEND            0x52
110 #define SC_FWD_OPEN              0x54
111
112
113
114 /* CIP Genral status codes */
115 #define CI_GRC_SUCCESS              0x00
116 #define CI_GRC_FAILURE              0x01
117 #define CI_GRC_NO_RESOURCE          0x02
118 #define CI_GRC_BAD_DATA             0x03
119 #define CI_GRC_BAD_PATH             0x04
120 #define CI_GRC_BAD_CLASS_INSTANCE   0x05
121 #define CI_GRC_PARTIAL_DATA         0x06
122 #define CI_GRC_CONN_LOST            0x07
123 #define CI_GRC_BAD_SERVICE          0x08
124 #define CI_GRC_BAD_ATTR_DATA        0x09
125 #define CI_GRC_ATTR_LIST_ERROR      0x0A
126 #define CI_GRC_ALREADY_IN_MODE      0x0B
127 #define CI_GRC_BAD_OBJ_MODE         0x0C
128 #define CI_GRC_OBJ_ALREADY_EXISTS   0x0D
129 #define CI_GRC_ATTR_NOT_SETTABLE    0x0E
130 #define CI_GRC_PERMISSION_DENIED    0x0F
131 #define CI_GRC_DEV_IN_WRONG_STATE   0x10
132 #define CI_GRC_REPLY_DATA_TOO_LARGE 0x11
133 #define CI_GRC_FRAGMENT_PRIMITIVE   0x12
134 #define CI_GRC_CONFIG_TOO_SMALL     0x13
135 #define CI_GRC_UNDEFINED_ATTR       0x14
136 #define CI_GRC_CONFIG_TOO_BIG       0x15
137 #define CI_GRC_OBJ_DOES_NOT_EXIST   0x16
138 #define CI_GRC_NO_FRAGMENTATION     0x17
139 #define CI_GRC_DATA_NOT_SAVED       0x18
140 #define CI_GRC_DATA_WRITE_FAILURE   0x19
141 #define CI_GRC_REQUEST_TOO_LARGE    0x1A
142 #define CI_GRC_RESPONSE_TOO_LARGE   0x1B
143 #define CI_GRC_MISSING_LIST_DATA    0x1C
144 #define CI_GRC_INVALID_LIST_STATUS  0x1D
145 #define CI_GRC_SERVICE_ERROR        0x1E
146 #define CI_GRC_CONN_RELATED_FAILURE 0x1F
147 #define CI_GRC_INVALID_PARAMETER    0x20
148 #define CI_GRC_WRITE_ONCE_FAILURE   0x21
149 #define CI_GRC_INVALID_REPLY        0x22
150 #define CI_GRC_BAD_KEY_IN_PATH      0x25
151 #define CI_GRC_BAD_PATH_SIZE        0x26
152 #define CI_GRC_UNEXPECTED_ATTR      0x27
153 #define CI_GRC_INVALID_MEMBER       0x28
154 #define CI_GRC_MEMBER_NOT_SETTABLE  0x29
155
156 #define CI_GRC_STILL_PROCESSING     0xFF
157
158
159 /* IOI Path types */
160 #define CI_SEGMENT_TYPE_MASK        0xE0
161
162 #define CI_PATH_SEGMENT             0x00
163 #define CI_LOGICAL_SEGMENT          0x20
164 #define CI_NETWORK_SEGMENT          0x40
165 #define CI_SYMBOLIC_SEGMENT         0x60
166 #define CI_DATA_SEGMENT             0x80
167
168 #define CI_LOGICAL_SEG_TYPE_MASK    0x1C
169 #define CI_LOGICAL_SEG_CLASS_ID     0x00
170 #define CI_LOGICAL_SEG_INST_ID      0x04
171 #define CI_LOGICAL_SEG_MBR_ID       0x08
172 #define CI_LOGICAL_SEG_CON_POINT    0x0C
173 #define CI_LOGICAL_SEG_ATTR_ID      0x10
174 #define CI_LOGICAL_SEG_SPECIAL      0x14
175 #define CI_LOGICAL_SEG_SERV_ID      0x18
176 #define CI_LOGICAL_SEG_RES_1        0x1C
177
178 #define CI_LOGICAL_SEG_FORMAT_MASK  0x03
179 #define CI_LOGICAL_SEG_8_BIT        0x00
180 #define CI_LOGICAL_SEG_16_BIT       0x01
181 #define CI_LOGICAL_SEG_32_BIT       0x02
182 #define CI_LOGICAL_SEG_RES_2        0x03
183 #define CI_LOGICAL_SEG_E_KEY        0x00
184
185 #define CI_E_KEY_FORMAT_VAL         0x04
186
187 #define CI_DATA_SEG_SIMPLE          0x80
188 #define CI_DATA_SEG_SYMBOL          0x91
189
190
191 /* Device Profile:s */
192 #define DP_GEN_DEV                           0x00
193 #define DP_AC_DRIVE                             0x02
194 #define DP_MOTOR_OVERLOAD                    0x03
195 #define DP_LIMIT_SWITCH                      0x04
196 #define DP_IND_PROX_SWITCH                   0x05
197 #define DP_PHOTO_SENSOR                      0x06
198 #define DP_GENP_DISC_IO                      0x07
199 #define DP_RESOLVER                          0x09
200 #define DP_COM_ADAPTER                       0x0C
201 #define DP_POS_CNT                           0x10
202 #define DP_DC_DRIVE                          0x13
203 #define DP_CONTACTOR                         0x15
204 #define DP_MOTOR_STARTER                     0x16
205 #define DP_SOFT_START                        0x17
206 #define DP_HMI                               0x18
207 #define DP_MASS_FLOW_CNT                     0x1A
208 #define DP_PNEUM_VALVE                       0x1B
209 #define DP_VACUUM_PRES_GAUGE                 0x1C
210
211
212
213 /* Initialize the protocol and registered fields */
214 static int proto_cipencap              = -1;
215 static int hf_enip_command             = -1;
216 static int hf_enip_ifacehnd            = -1;
217
218 static int hf_enip_cpf_typeid          = -1;
219
220 static int hf_enip_ucm_sc              = -1;
221 static int hf_enip_ucm_rr              = -1;
222 static int hf_enip_ucm_path            = -1;
223 static int hf_enip_ucm_genstat         = -1;
224 static int hf_enip_cpf_lir_sinfamily   = -1;
225 static int hf_enip_cpf_lir_sinport     = -1;
226 static int hf_enip_cpf_lir_sinaddr     = -1;
227 static int hf_enip_cpf_lir_sinzero     = -1;
228 static int hf_enip_cpf_lir_devtype     = -1;
229 static int hf_enip_cpf_lir_prodcode    = -1;
230 static int hf_enip_cpf_lir_status      = -1;
231 static int hf_enip_cpf_lir_sernbr      = -1;
232 static int hf_enip_cpf_lir_namelength  = -1;
233 static int hf_enip_cpf_lir_name        = -1;
234 static int hf_enip_cpf_lir_state       = -1;
235
236 static int hf_enip_cpf_sat_connid      = -1;
237 static int hf_enip_cpf_sat_seqnum      = -1;
238
239 static int hf_enip_vendors             = -1;
240
241 static int hf_enip_ucm_fwo_comp        = -1;
242 static int hf_enip_ucm_fwo_mrev        = -1;
243
244 static int hf_enip_ucm_fwo_con_size    = -1;
245 static int hf_enip_ucm_fwo_fixed_var   = -1;
246 static int hf_enip_ucm_fwo_prio        = -1;
247 static int hf_enip_ucm_fwo_typ         = -1;
248 static int hf_enip_ucm_fwo_own         = -1;
249
250 static int hf_enip_cpf_lsr_tcp         = -1;
251 static int hf_enip_cpf_lsr_udp         = -1;
252
253
254 /* Initialize the subtree pointers */
255 static gint ett_cipencap   = -1;
256 static gint ett_cip        = -1;
257 static gint ett_cpf        = -1;
258 static gint ett_path       = -1;
259 static gint ett_ekey_path  = -1;
260 static gint ett_cia_path   = -1;
261 static gint ett_data_seg   = -1;
262
263 static gint ett_cipencaph  = -1;
264 static gint ett_csf        = -1;
265 static gint ett_rrsc       = -1;
266 static gint ett_sockadd    = -1;
267 static gint ett_mcsc       = -1;
268 static gint ett_ncp        = -1;
269 static gint ett_lsrcf      = -1;
270 static gint ett_mes_req    = -1;
271 static gint ett_cmd_data   = -1;
272 static gint ett_port_path  = -1;
273 static gint ett_mult_ser   = -1;
274
275
276
277 /* Translate function to string - Encapsulation commands */
278 static const value_string encap_cmd_vals[] = {
279         { NOP,                        "NOP"                },
280         { LIST_SERVICES,           "List Services"      },
281         { LIST_IDENTITY,                "List Identity"      },
282         { LIST_INTERFACES,      "List Interfaces"    },
283         { REGISTER_SESSION,     "Register Session"   },
284         { UNREGISTER_SESSION,"Unregister Session" },
285         { SEND_RR_DATA,         "Send RR Data"       },
286         { SEND_UNIT_DATA,               "Send Unit Data"     },
287         { INDICATE_STATUS,      "Indicate Status"    },
288         { CANCEL,                     "Cancel"             },
289
290         { 0,                                  NULL                 }
291 };
292
293
294 /* Translate function to string - Encapsulation status */
295 static const value_string encap_status_vals[] = {
296         { SUCCESS,                            "Success" },
297         { INVALID_CMD,           "Invalid Command" },
298         { NO_RESOURCES,            "No Memory Resources" },
299         { INCORRECT_DATA,             "Incorrect Data" },
300         { INVALID_SESSION,         "Invalid Session Handle" },
301         { INVALID_LENGTH,       "Invalid Length" },
302         { UNSUPPORTED_PROT_REV, "Unsupported Protocol Revision" },
303
304         { 0,                                     NULL }
305 };
306
307 /* Translate function to Common data format values */
308 static const value_string cdf_type_vals[] = {
309         { CDF_NULL,                           "Null Address Item" },
310         { LIST_IDENTITY_RESP,   "List Identity Response" },
311         { CONNECTION_BASED,             "Connected Address Item" },
312         { CONNECTION_TRANSPORT, "Connected Data Item" },
313         { UNCONNECTED_MSG,         "Unconnected Data Item" },
314         { LIST_SERVICES_RESP,   "List Services Response" },
315         { SOCK_ADR_INFO_OT,        "Socket Address Info O->T" },
316         { SOCK_ADR_INFO_TO,        "Socket Address Info T->O" },
317         { SEQ_ADDRESS,           "Sequenced Address Item" },
318
319         { 0,                                     NULL }
320 };
321
322 /* Translate function to string - CIP Service codes */
323 static const value_string encap_sc_vals[] = {
324         { SC_GET_ATT_ALL,                "Get Attribute All" },
325         { SC_SET_ATT_ALL,                "Set Attribute All" },
326         { SC_GET_ATT_LIST,            "Get Attribute List" },
327         { SC_SET_ATT_LIST,            "Set Attribute List" },
328         { SC_RESET,                    "Reset" },
329    { SC_START,                 "Start" },
330    { SC_STOP,                  "Stop" },
331    { SC_CREATE,             "Create" },
332    { SC_DELETE,             "Delete" },
333    { SC_APPLY_ATTRIBUTES,          "Apply Attributes" },
334         { SC_GET_ATT_SINGLE,          "Get Attribute Single" },
335         { SC_SET_ATT_SINGLE,          "Set Attribute Single" },
336    { SC_FIND_NEXT_OBJ_INST,     "Find Next Object Instance" },
337    { SC_RESTOR,             "Restore" },
338         { SC_SAVE,                     "Save" },
339         { SC_NO_OP,                    "Nop" },
340         { SC_GET_MEMBER,                 "Get Member" },
341         { SC_SET_MEMBER,                 "Set Member" },
342         { SC_MULT_SERV_PACK,       "Multiple Service Packet" },
343
344         /* Some class specific services */
345         { SC_FWD_CLOSE,          "Forward Close" },
346         { SC_FWD_OPEN,              "Forward Open" },
347         { SC_UNCON_SEND,           "Unconnected Send" },
348
349         { 0,                                        NULL }
350 };
351
352 /* Translate function to string - CIP Request/Response */
353 static const value_string encap_sc_rr[] = {
354         { 0,          "Request"  },
355         { 1,          "Response" },
356
357         { 0,                    NULL }
358 };
359
360
361 /* Translate function to string - Compatibility */
362 static const value_string enip_com_bit_vals[] = {
363         { 0,          "Bit Cleared" },
364         { 1,          "Bit Set"     },
365
366         { 0,        NULL          }
367 };
368
369 /* Translate function to string - True/False */
370 static const value_string enip_true_false_vals[] = {
371         { 0,          "False"       },
372         { 1,          "True"        },
373
374         { 0,        NULL          }
375 };
376
377
378 /* Translate function to string - Connection priority */
379 static const value_string enip_con_prio_vals[] = {
380         { 0,          "Low Priority"  },
381         { 1,          "High Priority" },
382         { 2,          "Scheduled"     },
383         { 3,          "Urgent"        },
384
385         { 0,        NULL            }
386 };
387
388
389 /* Translate function to string - Connection size fixed or variable */
390 static const value_string enip_con_fw_vals[] = {
391         { 0,          "Fixed"    },
392         { 1,          "Variable" },
393
394         { 0,        NULL       }
395 };
396
397
398 /* Translate function to string - Connection owner */
399 static const value_string enip_con_owner_vals[] = {
400         { 0,          "Exclusive" },
401         { 1,          "Redundant" },
402
403         { 0,        NULL        }
404 };
405
406
407 /* Translate function to string - Connection type */
408 static const value_string enip_con_type_vals[] = {
409         { 0,          "Null"           },
410         { 1,          "Multicast"      },
411         { 2,          "Point to Point" },
412         { 3,          "Reserved"       },
413
414         { 0,        NULL             }
415 };
416
417 /* Translate function to string - Timeout Multiplier */
418 static const value_string enip_con_time_mult_vals[] = {
419         { 0,        "*4"   },
420         { 1,        "*8"   },
421         { 2,        "*16"  },
422         { 3,        "*32"  },
423         { 4,        "*64"  },
424         { 5,        "*128" },
425         { 6,        "*256" },
426         { 7,        "*512" },
427
428    { 0,        NULL    }
429 };
430
431
432 /* Translate function to string - CIP General Status codes */
433 static const value_string encap_cip_gs_vals[] = {
434         { CI_GRC_SUCCESS,             "Success" },
435    { CI_GRC_FAILURE,             "Connection failure" },
436    { CI_GRC_NO_RESOURCE,         "Resource(s) unavailable" },
437    { CI_GRC_BAD_DATA,            "Obj specific data bad" },
438    { CI_GRC_BAD_PATH,            "Bad path segment" },
439    { CI_GRC_BAD_CLASS_INSTANCE,  "Class/Instance unknown" },
440    { CI_GRC_PARTIAL_DATA,        "Not all expected data sent" },
441    { CI_GRC_CONN_LOST,           "Messaging connection lost" },
442    { CI_GRC_BAD_SERVICE,         "Unimplemented service code" },
443    { CI_GRC_BAD_ATTR_DATA,       "Bad attribute data value" },
444    { CI_GRC_ATTR_LIST_ERROR,     "Get/Set attr list failed" },
445    { CI_GRC_ALREADY_IN_MODE,     "Obj already in requested mode" },
446    { CI_GRC_BAD_OBJ_MODE,        "Obj not in proper mode" },
447    { CI_GRC_OBJ_ALREADY_EXISTS,  "Object already created" },
448    { CI_GRC_ATTR_NOT_SETTABLE,   "Set of get only attr tried" },
449    { CI_GRC_PERMISSION_DENIED,   "Insufficient access permission" },
450    { CI_GRC_DEV_IN_WRONG_STATE,  "Device not in proper mode" },
451    { CI_GRC_REPLY_DATA_TOO_LARGE,"Response packet too large" },
452    { CI_GRC_FRAGMENT_PRIMITIVE,  "Primitive value will fragment" },
453    { CI_GRC_CONFIG_TOO_SMALL,    "Configuration too small" },
454    { CI_GRC_UNDEFINED_ATTR,      "Attribute is undefined" },
455    { CI_GRC_CONFIG_TOO_BIG,      "Configuration too big" },
456    { CI_GRC_OBJ_DOES_NOT_EXIST,  "Non-existant object specified" },
457    { CI_GRC_NO_FRAGMENTATION,    "Fragmentation not active" },
458    { CI_GRC_DATA_NOT_SAVED,      "Attr data not previously saved" },
459    { CI_GRC_DATA_WRITE_FAILURE,  "Attr data not saved this time" },
460    { CI_GRC_REQUEST_TOO_LARGE,   "Routing failure on request" },
461    { CI_GRC_RESPONSE_TOO_LARGE,  "Routing failure on response" },
462    { CI_GRC_MISSING_LIST_DATA,   "Attr data not found in list" },
463    { CI_GRC_INVALID_LIST_STATUS, "Returned list of attr w/status" },
464    { CI_GRC_SERVICE_ERROR,       "Embedded service failed" },
465    { CI_GRC_CONN_RELATED_FAILURE,"Error in conn processing" },
466    { CI_GRC_INVALID_PARAMETER,   "Param associated with req inv" },
467    { CI_GRC_WRITE_ONCE_FAILURE,  "Write once previously done" },
468    { CI_GRC_INVALID_REPLY,       "Invalid reply received" },
469    { CI_GRC_BAD_KEY_IN_PATH,     "Electronic key in path failed" },
470    { CI_GRC_BAD_PATH_SIZE,       "Invalid path size" },
471    { CI_GRC_UNEXPECTED_ATTR,     "Cannot set attr at this time" },
472    { CI_GRC_INVALID_MEMBER,      "Member ID in list nonexistant" },
473    { CI_GRC_MEMBER_NOT_SETTABLE, "Cannot set value of member" },
474
475         { 0,                                           NULL }
476 };
477
478
479 /* Translate Vendor ID:s */
480 static const value_string encap_cip_vendor_vals[] = {
481    { 1,     "Rockwell Automation/Allen-Bradley"                   },
482    { 5,     "Rockwell Automation/Reliance Electric"               },
483    { 40,    "WAGO Corporation"                                    },
484    { 49,    "Grayhill Inc."                                       },
485    { 50,    "Real Time Automation (C&ID)"                         },
486    { 52,    "Numatics, Inc."                                      },
487    { 57,    "Pepperl + Fuchs"                                     },
488    { 81,    "IXXAT Automation GmbH"                               },
489    { 90,    "HMS Industrial Networks AB"                          },
490    { 96,    "Digital Electronics Corp"                            },
491    { 133,   "Balogh T.A.G., Corporation"                          },
492    { 170,   "Pyramid Solutions, Inc."                             },
493    { 256,   "InterlinkBT LLC"                                     },
494    { 258,   "Hardy Instruments, Inc."                             },
495    { 283,   "Hilscher GmbH"                                       },
496    { 287,   "Bosch Rexroth Corporation, Indramat"                 },
497    { 356,   "Fanuc Robotics America"                              },
498    { 579,   "Applicom international"                              },
499    { 588,   "West Instruments Limited"                            },
500    { 590,   "Delta Computer Systems Inc."                         },
501    { 596,   "Wire-Pro, Inc."                                      },
502    { 635,   "The Siemon Company"                                  },
503    { 638,   "Woodhead Connectivity"                               },
504    { 651,   "Fife Corporation"                                    },
505    { 668,   "Rockwell Automation/Entek IRD Intl."                 },
506    { 678,   "Cognex Corporation"                                  },
507    { 734,   "Hakko Electronics Co., Ltd"                          },
508    { 735,   "Tang & Associates"                                   },
509    { 743,   "Linux Network Services"                              },
510    { 748,   "DVT Corporation"                                     },
511    { 759,   "FLS Automation A/S"                                  },
512    { 768,   "CSIRO Mining Automation"                             },
513    { 778,   "Harting, Inc. NA"                                    },
514    { 784,   "Ci Technologies Pty Ltd (for Pelamos Industries)"    },
515    { 796,   "Siemens Energy & Automation, Inc."                   },
516    { 798,   "Tyco Electronics"                                    },
517    { 803,   "ICP DAS Co., LTD"                                    },
518    { 805,   "Digi International, Inc."                            },
519    { 812,   "Process Control Corporation"                         },
520    { 832,   "Quest Technical Solutions, Inc."                     },
521    { 841,   "Panduit Corporation"                                 },
522    { 850,   "Datalogic, Inc."                                     },
523    { 851,   "SoftPLC Corporation"                                 },
524    { 857,   "RVSI"                                                },
525    { 859,   "Tennessee Rand Automation"                           },
526
527         { 0,            NULL                                                  }
528 };
529
530 /* Translate Device Profile:s */
531 static const value_string encap_cip_devtype_vals[] = {
532    { DP_GEN_DEV,              "Generic Device"              },
533    { DP_AC_DRIVE,             "AC Drive"                    },
534    { DP_MOTOR_OVERLOAD,       "Motor Overload"              },
535    { DP_LIMIT_SWITCH,         "Limit Switch"                },
536    { DP_IND_PROX_SWITCH,      "Inductive Proximity Switch"  },
537    { DP_PHOTO_SENSOR,         "Photoelectric Sensor"        },
538    { DP_GENP_DISC_IO,         "General Purpose Dicrete I/O" },
539    { DP_RESOLVER,             "Resolver"                    },
540    { DP_COM_ADAPTER,          "Communications Adapter"      },
541    { DP_POS_CNT,              "Position Controller",        },
542    { DP_DC_DRIVE,             "DC Drive"                    },
543    { DP_CONTACTOR,            "Contactor",                  },
544    { DP_MOTOR_STARTER,        "Motor Starter",              },
545    { DP_SOFT_START,           "Soft Start",                 },
546    { DP_HMI,                  "Human-Machine Interface"     },
547    { DP_MASS_FLOW_CNT,        "Mass Flow Controller"        },
548    { DP_PNEUM_VALVE,          "Pneumatic Valve"             },
549    { DP_VACUUM_PRES_GAUGE,    "Vaccuum Pressure Gauge"      },
550
551    { 0,                                     NULL                          }
552 };
553
554
555 /* Translate class names */
556 static const value_string enip_class_names_vals[] = {
557         { 0x01,     "Identity Object"                       },
558         { 0x02,     "Message Router"                        },
559         { 0x03,     "DeviceNet Object"                      },
560         { 0x04,     "Assembly Object"                       },
561         { 0x05,     "Connection Object"                     },
562         { 0x06,     "Connection Manager"                    },
563         { 0x07,     "Register Object"                       },
564         { 0x08,     "Discrete Input Point Object"           },
565         { 0x09,     "Discrete Output Point Object"          },
566         { 0x0A,     "Analog Input Point Object"             },
567         { 0x0B,     "Analog Output Point Object"            },
568         { 0x0E,     "Presence Sensing Object"               },
569         { 0x0F,     "Parameter Object"                      },
570         { 0x10,     "Parameter Group Object"                },
571         { 0x12,     "Group Object"                          },
572         { 0x1D,     "Discrete Input Group Object"           },
573         { 0x1E,     "Discrete Output Group Object"          },
574         { 0x1F,     "Discrete Group Object"                 },
575         { 0x20,     "Analog Input Group Object"             },
576         { 0x21,     "Analog Output Group Object"            },
577         { 0x22,     "Analog Group Object"                   },
578         { 0x23,     "Position Sensor Object"                },
579         { 0x24,     "Position Controller Supervisor Object" },
580         { 0x25,     "Position Controller Object"            },
581         { 0x26,     "Block Sequencer Object"                },
582         { 0x27,     "Command Block Object"                  },
583         { 0x28,     "Motor Data Object"                     },
584         { 0x29,     "Control Supervisor Object"             },
585         { 0x2A,     "AC/DC Drive Object"                    },
586         { 0x2B,     "Acknowledge Handler Object"            },
587         { 0x2C,     "Overload Object"                       },
588         { 0x2D,     "Softstart Object"                      },
589         { 0x2E,     "Selection Object"                      },
590         { 0x30,     "S-Device Supervisor Object"            },
591         { 0x31,     "S-Analog Sensor Object"                },
592         { 0x32,     "S-Analog Actuator Object"              },
593         { 0x33,     "S-Single Stage Controller Object"      },
594         { 0x34,     "S-Gas Calibration Object"              },
595         { 0x35,     "Trip Point Object"                     },
596         { 0xF0,     "ControlNet Object"                     },
597         { 0xF1,     "ControlNet Keeper Object"              },
598         { 0xF2,     "ControlNet Scheduling Object"          },
599         { 0xF3,     "Connection Configuration Object"       },
600         { 0xF4,     "Port Object"                           },
601         { 0xF5,     "TCP/IP Interface Object"               },
602         { 0xF6,     "EtherNet Link Object"                  },
603
604         { 0,                    NULL                                    }
605 };
606
607
608
609 static proto_item*
610 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
611 {
612   char   *tmp, *tmp2, *tmp2start;
613   proto_item* pi;
614   int          i,tmp_length;
615   guint32      octet;
616   /* At least one version of Apple's C compiler/linker is buggy, causing
617      a complaint from the linker about the "literal C string section"
618      not ending with '\0' if we initialize a 16-element "char" array with
619      a 16-character string, the fact that initializing such an array with
620      such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
621      '\0' byte in the string nonwithstanding. */
622   static const char my_hex_digits[16] =
623       { '0', '1', '2', '3', '4', '5', '6', '7',
624         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
625
626
627
628    if( ( length * 2 ) > 32 )
629    {
630       tmp2 = (char*)g_malloc( 36 );
631       tmp_length = 16;
632    }
633    else
634    {
635       tmp2 = (char*)g_malloc( ( length * 2 ) + 1 );
636       tmp_length = length;
637    }
638
639    tmp2start = tmp2;
640
641    tmp = (char*)g_malloc( tmp_length );
642    tvb_memcpy( tvb, tmp, start, tmp_length );
643
644    for( i = 0; i < tmp_length; i++ )
645    {
646       octet = tmp[i];
647       octet >>= 4;
648       *tmp2++ = my_hex_digits[octet&0xF];
649       octet = tmp[i];
650       *tmp2++ = my_hex_digits[octet&0xF];
651    }
652
653    if( tmp_length != length )
654    {
655       *tmp2++ = '.';
656       *tmp2++ = '.';
657       *tmp2++ = '.';
658    }
659
660    *tmp2 = 0;
661
662    pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
663
664    g_free( tmp );
665    g_free( tmp2start );
666
667    return( pi );
668
669 } /* end of add_byte_array_text_to_proto_tree() */
670
671
672
673 /* Decode and add epath to tree */
674 static void
675 show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
676 {
677    int pathpos;
678    int temp_data;
679    int temp_data2;
680    unsigned char segment_type, temp_byte, opt_link_size;
681    proto_tree *path_tree, *port_tree;
682    proto_item *qi, *cia_item, *ds_item;
683    proto_tree *e_key_tree, *cia_tree, *ds_tree;
684    proto_item *mcpi, *temp_item, *port_item, *ext_link_item;
685    proto_tree *mc_tree;
686    int seg_size, i, temp_word;
687    char *temp_string;
688
689    /* Create a sub tree for the epath */
690    path_tree = proto_item_add_subtree( pi, ett_path );
691
692    proto_tree_add_item_hidden(path_tree, hf_enip_ucm_path,
693                                                            tvb, offset, path_length, TRUE );
694
695    pathpos = 0;
696
697    while( pathpos < path_length )
698    {
699       /* Get segement type */
700       segment_type = tvb_get_guint8( tvb, offset + pathpos );
701
702       /* Determine the segment type */
703
704       switch( segment_type & CI_SEGMENT_TYPE_MASK )
705       {
706       case CI_PATH_SEGMENT:
707
708          port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment (0x00)" );
709          port_tree = proto_item_add_subtree( port_item, ett_port_path );
710
711          /* Add Extended Link Address Size */
712          temp_item = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: " );
713
714          if( segment_type & 0x10 )
715          {
716             proto_item_append_text(temp_item, "TRUE");
717             opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
718
719             proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size  );
720             ext_link_item = proto_tree_add_text( port_tree, tvb, offset+pathpos+2, opt_link_size, "Link Address: " );
721
722             /* Add extended link address */
723             for( i=0; i < opt_link_size; i++ )
724             {
725                temp_byte = tvb_get_guint8( tvb, offset + pathpos+2+i );
726                proto_item_append_text(ext_link_item, "%c", temp_byte );
727             }
728
729             /* Pad byte */
730             if( opt_link_size % 2 )
731             {
732               pathpos = pathpos + 3 + opt_link_size;
733               proto_item_set_len(port_item, 3+opt_link_size);
734             }
735             else
736             {
737               pathpos = pathpos + 2 + opt_link_size;
738               proto_item_set_len(port_item, 2+opt_link_size);
739             }
740
741          }
742          else
743          {
744             proto_item_append_text(temp_item, "FALSE");
745             proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Port Identifier: %d", (segment_type & 0x0F)  );
746             proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address: %d", tvb_get_guint8( tvb, offset + pathpos + 1 )  );
747             proto_item_set_len(port_item, 2);
748             pathpos += 2;
749          }
750
751          break;
752
753       case CI_LOGICAL_SEGMENT:
754
755          /* Logical segment, determin the logical type */
756
757          switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
758          {
759          case CI_LOGICAL_SEG_CLASS_ID:
760
761             /* Logical Class ID, do a format check */
762
763                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
764                    {
765                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
766                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Class Segment (0x%02X)", segment_type );
767
768                /* Create a sub tree for the class */
769                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
770
771                /* Display the 8-bit class number */
772                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Class: %s (0x%02X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
773
774                temp_string = match_strval( temp_data, enip_class_names_vals );
775
776                if( temp_string )
777                {
778                   proto_item_append_text(pi, "%s", temp_string );
779                }
780                else
781                {
782                   proto_item_append_text(pi, "Class: 0x%02X", temp_data );
783                }
784
785                /* 2 bytes of path used */
786                pathpos += 2;
787             }
788             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
789             {
790                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
791                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Class Segment (0x%02X)", segment_type );
792
793                /* Create a sub tree for the class */
794                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
795
796                /* Display the 16-bit class number */
797                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Class: %s (0x%04X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
798                temp_string = match_strval( temp_data, enip_class_names_vals );
799
800                if( temp_string )
801                {
802                   proto_item_append_text(pi, "%s", temp_string );
803                }
804                else
805                {
806                   proto_item_append_text(pi, "Class: 0x%04X", temp_data );
807                }
808
809                /* 4 bytes of path used */
810                pathpos += 4;
811             }
812             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
813             {
814                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
815                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
816
817                /* Create a sub tree for the class */
818                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
819
820                /* Display the 32-bit instance number */
821                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Class: %s (0x%08X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
822                temp_string = match_strval( temp_data, enip_class_names_vals );
823
824                if( temp_string )
825                {
826                   proto_item_append_text(pi, "%s", temp_string );
827                }
828                else
829                {
830                   proto_item_append_text(pi, "Class: 0x%08X", temp_data );
831                }
832
833                /* 6 bytes of path used */
834                pathpos += 6;
835             }
836             else
837             {
838                /* Unsupported logical segment format */
839                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
840                return;
841             }
842             break;
843
844
845          case CI_LOGICAL_SEG_INST_ID:
846
847             /* Logical Instance ID, do a format check */
848
849                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
850                    {
851                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
852                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Instance Segment (0x%02X)", segment_type );
853
854                /* Create a sub tree for the instance */
855                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
856
857                /* Display the 8-bit instance number */
858                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Instance: 0x%02X", temp_data );
859                proto_item_append_text(pi, ", Inst: 0x%02X", temp_data );
860
861                /* 2 bytes of path used */
862                pathpos += 2;
863             }
864             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
865             {
866                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
867                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
868
869                /* Create a sub tree for the instance */
870                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
871
872                /* Display the 16-bit instance number */
873                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Instance: 0x%04X", temp_data );
874                proto_item_append_text(pi, ", Inst: 0x%04X", temp_data );
875
876                /* 4 bytes of path used */
877                pathpos += 4;
878             }
879             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
880             {
881                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
882                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
883
884                /* Create a sub tree for the instance */
885                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
886
887                /* Display the 16-bit instance number */
888                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Instance: 0x%08X", temp_data );
889                proto_item_append_text(pi, ", Inst: 0x%08X", temp_data );
890
891                /* 6 bytes of path used */
892                pathpos += 6;
893             }
894             else
895             {
896                /* Unsupported logical segment format */
897                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
898                return;
899             }
900             break;
901
902
903          case CI_LOGICAL_SEG_ATTR_ID:
904
905             /* Logical Attribute ID, do a format check */
906
907                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
908                    {
909                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
910                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Attribute Segment (0x%02X)", segment_type );
911
912                /* Create a sub tree for the attribute */
913                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
914
915                /* Display the 8-bit instance number */
916                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Attribute: 0x%02X", temp_data );
917                proto_item_append_text(pi, ", Att: 0x%02X", temp_data );
918
919                /* 2 bytes of path used */
920                pathpos += 2;
921             }
922             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
923             {
924                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
925                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
926
927                /* Create a sub tree for the attribute */
928                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
929
930                /* Display the 16-bit instance number */
931                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Attribute: 0x%04X", temp_data );
932                proto_item_append_text(pi, ", Att: 0x%04X", temp_data );
933
934                /* 4 bytes of path used */
935                pathpos += 4;
936             }
937             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
938             {
939                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
940                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
941
942                /* Create a sub tree for the attribute */
943                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
944
945                /* Display the 16-bit instance number */
946                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Attribute: 0x%08X", temp_data );
947                proto_item_append_text(pi, ", Att: 0x%08X", temp_data );
948
949                /* 6 bytes of path used */
950                pathpos += 6;
951             }
952             else
953             {
954                /* Unsupported logical segment format */
955                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
956                return;
957             }
958             break;
959
960
961          case CI_LOGICAL_SEG_CON_POINT:
962
963             /* Logical Connection point , do a format check */
964
965                    if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
966                    {
967                       temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
968                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-Bit Logical Connection Point Segment (0x%02X)", segment_type );
969
970                /* Create a sub tree for the connection point */
971                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
972
973                /* Display the 8-bit instance number */
974                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Connection Point: 0x%02X", temp_data );
975                proto_item_append_text(pi, ", ConPnt: 0x%02X", temp_data );
976
977                /* 2 bytes of path used */
978                pathpos += 2;
979             }
980             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
981             {
982                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
983                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Connection Point Segment (0x%02X)", segment_type );
984
985                /* Create a sub tree for the connection point */
986                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
987
988                /* Display the 16-bit instance number */
989                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Connection Point: 0x%04X", temp_data );
990                proto_item_append_text(pi, ", ConPnt: 0x%04X", temp_data );
991
992                /* 4 bytes of path used */
993                pathpos += 4;
994             }
995             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
996             {
997                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
998                cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Connection Point Segment (0x%02X)", segment_type );
999
1000                /* Create a sub tree for the connection point */
1001                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
1002
1003                /* Display the 16-bit instance number */
1004                proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Connection Point (0x%08X)", temp_data );
1005                proto_item_append_text(pi, ", ConPnt: 0x%08X", temp_data );
1006
1007                /* 6 bytes of path used */
1008                pathpos += 6;
1009             }
1010             else
1011             {
1012                /* Unsupported logical segment format */
1013                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
1014                return;
1015             }
1016             break;
1017
1018
1019          case CI_LOGICAL_SEG_SPECIAL:
1020
1021             /* Logical Special ID, the only logical format sepcifyed is electronic key */
1022
1023             if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
1024             {
1025
1026                /* Get the Key Format */
1027
1028                temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
1029
1030                if( temp_data == CI_E_KEY_FORMAT_VAL )
1031                {
1032                   qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
1033
1034                   /* Create a sub tree for the IOI */
1035                   e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
1036
1037                   /* Print the key type */
1038                   proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
1039
1040                   /* Get the Vendor ID */
1041                       temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
1042                   proto_tree_add_item( e_key_tree, hf_enip_vendors, tvb, offset + pathpos + 2, 2, TRUE);
1043                   proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
1044
1045                   /* Get Device Type */
1046                          temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
1047                          proto_tree_add_item( e_key_tree, hf_enip_cpf_lir_devtype, tvb, offset + pathpos + 4, 2, TRUE);
1048                   proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
1049
1050                   /* Product Code */
1051                          temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
1052                   proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
1053
1054                   /* Major revision/Compatibility */
1055                          temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
1056
1057                                         /* Add Major revision/Compatibility tree */
1058                                         mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
1059                                         mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
1060
1061                                         /* Add Compatibility bit info */
1062                   proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_comp,
1063                                                         tvb, offset + pathpos + 8, 1, TRUE );
1064
1065                   proto_item_append_text( mcpi, "%s, Major Revision: %d",
1066                               val_to_str( ( temp_data & 0x80 )>>7, enip_com_bit_vals , "" ),
1067                               temp_data & 0x7F );
1068
1069                                         /* Major revision */
1070                                         proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_mrev,
1071                                                         tvb, offset + pathpos + 8, 1, TRUE );
1072
1073                   /* Minor revision */
1074                   temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
1075                   proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
1076
1077                   proto_item_append_text( qi, ", V.%d.%d", ( temp_data & 0x7F ), temp_data2 );
1078
1079                   /* Increment the path pointer */
1080                   pathpos += 10;
1081
1082                }
1083                else
1084                {
1085                   /* Unsupported electronic key format */
1086                   proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
1087                   return;
1088                }
1089
1090             }
1091             else
1092             {
1093                /* Unsupported special segment format */
1094                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
1095                return;
1096             }
1097             break;
1098
1099
1100          default:
1101
1102             /* Unsupported logical segment type */
1103             proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
1104             return;
1105
1106          } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
1107          break;
1108
1109
1110       case CI_DATA_SEGMENT:
1111
1112          /* Data segment, determin the logical type */
1113
1114          switch( segment_type )
1115          {
1116
1117             case CI_DATA_SEG_SIMPLE:
1118
1119                /* Simple data segment */
1120                ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
1121
1122                /* Create a sub tree */
1123                ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
1124
1125                /* Segment size */
1126                seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
1127                proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
1128
1129                /* Segment data  */
1130                if( seg_size != 0 )
1131                {
1132                   qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
1133
1134                   for( i=0; i < seg_size/2; i ++ )
1135                   {
1136                     temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
1137                     proto_item_append_text(qi, " 0x%04X", temp_word );
1138                   }
1139
1140                   proto_item_set_len(qi, seg_size);
1141                }
1142
1143                proto_item_set_len( ds_item, 2 + seg_size );
1144                pathpos = pathpos + 2 + seg_size;
1145
1146                break;
1147
1148             case CI_DATA_SEG_SYMBOL:
1149
1150                /* ANSI extended symbol segment */
1151                ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
1152
1153                /* Create a sub tree */
1154                ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
1155
1156                /* Segment size */
1157                seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
1158                proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
1159
1160                /* Segment data  */
1161                if( seg_size != 0 )
1162                {
1163                   qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
1164
1165                   for( i=0; i < seg_size; i++ )
1166                   {
1167                     temp_byte = tvb_get_guint8( tvb, offset + pathpos+2+i );
1168                     proto_item_append_text(qi, "%c", temp_byte );
1169                   }
1170
1171                   proto_item_set_len(qi, seg_size);
1172
1173                   if( seg_size %2 )
1174                   {
1175                      /* We have a PAD BYTE */
1176                      proto_tree_add_text( ds_tree, tvb, offset + pathpos+2+i, 1, "Pad Byte (0x%02X)",
1177                          tvb_get_guint8( tvb, offset + pathpos+2+i ) );
1178                      pathpos++;
1179                      seg_size++;
1180                   }
1181                }
1182
1183                proto_item_set_len( ds_item, 2 + seg_size );
1184                pathpos = pathpos + 2 + seg_size;
1185
1186                break;
1187
1188             default:
1189                proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
1190                return;
1191
1192             } /* End of switch sub-type */
1193
1194             break;
1195
1196       default:
1197
1198          /* Unsupported segment type */
1199          proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
1200          return;
1201
1202       } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
1203
1204    } /* end of while( pathpos < path_length ) */
1205
1206 } /* end of show_epath() */
1207
1208
1209
1210 static void
1211 add_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length )
1212 {
1213    proto_item *pi, *rrsci, *ncppi, *ar_item, *temp_item, *temp_item2;
1214         proto_tree *temp_tree;
1215    proto_tree *rrsci_tree;
1216    proto_tree *ncp_tree;
1217    proto_tree *cmd_data_tree;
1218         int req_path_size, conn_path_size, mr_req_path_size;
1219         int temp_data;
1220         unsigned char gen_stat;
1221    unsigned char add_stat_size;
1222    unsigned char temp_byte, route_path_size;
1223    unsigned char app_rep_size, i;
1224    int msg_req_siz, num_services, serv_offset;
1225
1226
1227    /* Add Service code & Request/Response tree */
1228         rrsci = proto_tree_add_text(item_tree, tvb, offset, 1, "Service: ");
1229         rrsci_tree = proto_item_add_subtree(rrsci, ett_rrsc);
1230
1231         /* Add Request/Response */
1232    proto_tree_add_item(rrsci_tree, hf_enip_ucm_rr,
1233                         tvb, offset, 1, TRUE );
1234
1235    proto_item_append_text( rrsci, "%s (%s)",
1236                val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1237                   encap_sc_vals , "Unknown Service Code (%x)"),
1238                val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
1239                   encap_sc_rr, "") );
1240
1241         /* Add Service code */
1242         proto_tree_add_item(rrsci_tree, hf_enip_ucm_sc,
1243                         tvb, offset, 1, TRUE );
1244
1245
1246         if( tvb_get_guint8( tvb, offset ) & 0x80 )
1247         {
1248            /* Response message */
1249
1250                 /* Add general status */
1251                 gen_stat = tvb_get_guint8( tvb, offset+2 );
1252
1253                 proto_tree_add_item(item_tree, hf_enip_ucm_genstat,
1254                         tvb, offset+2, 1, TRUE );
1255
1256       /* Add additional status size */
1257       temp_data = tvb_get_guint8( tvb, offset+3 );
1258       proto_tree_add_text( item_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)", temp_data );
1259
1260                 add_stat_size = tvb_get_guint8( tvb, offset+3 )*2;
1261
1262                 if( add_stat_size )
1263                 {
1264          /* Add additional status */
1265          pi = proto_tree_add_text( item_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
1266
1267          for( i=0; i < add_stat_size/2; i ++ )
1268          {
1269            proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
1270          }
1271                 }
1272
1273       /* If there is any command specific data create a sub-tree for it */
1274       if( ( item_length-4-add_stat_size ) != 0 )
1275       {
1276          pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific data" );
1277          cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1278
1279                    if( gen_stat == CI_GRC_SUCCESS )
1280                 {
1281                         /* Success responses */
1282
1283                         if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN )
1284             {
1285                /* Forward open Response (Success) */
1286
1287                /* Display originator to target connection ID */
1288                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size );
1289                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1290
1291                /* Display target to originator connection ID */
1292                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1293                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1294
1295                /* Display connection serial number */
1296                temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
1297                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", temp_data );
1298
1299                /* Display the originator vendor id */
1300                proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+10, 2, TRUE);
1301
1302                /* Display the originator serial number */
1303                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
1304                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", temp_data );
1305
1306                /* Display originator to target actual packet interval */
1307                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
1308                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 );
1309
1310                /* Display originator to target actual packet interval */
1311                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
1312                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 );
1313
1314                /* Display the application reply size */
1315                app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
1316                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1317
1318                /* Display the Reserved byte */
1319                temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
1320                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
1321
1322                if( app_rep_size != 0 )
1323                {
1324                   /* Display application Reply data */
1325                   ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
1326
1327                   for( i=0; i < app_rep_size; i++ )
1328                   {
1329                     temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
1330                     proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1331                   }
1332
1333                 } /* End of if reply data */
1334
1335             } /* End of if forward open response */
1336                         else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE )
1337             {
1338                /* Forward close response (Success) */
1339
1340                /* Display connection serial number */
1341                temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1342                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1343
1344                /* Display the originator vendor id */
1345                proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
1346
1347                /* Display the originator serial number */
1348                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1349                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1350
1351                /* Display the application reply size */
1352                app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
1353                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1354
1355                /* Display the Reserved byte */
1356                temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1357                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
1358
1359                if( app_rep_size != 0 )
1360                {
1361                   /* Display application Reply data */
1362                   ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
1363
1364                   for( i=0; i < app_rep_size; i ++ )
1365                   {
1366                     temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
1367                     proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1368                   }
1369
1370                 } /* End of if reply data */
1371
1372             } /* End of if forward close response */
1373             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1374             {
1375                /* Unconnected send response (Success) */
1376
1377                /* Display service response data */
1378                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1379             }
1380             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
1381             {
1382                /* Multiple Service Reply (Success)*/
1383
1384                /* Add number of replies */
1385                num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
1386                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
1387
1388                /* Add replies */
1389                temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
1390
1391                for( i=0; i < num_services; i++ )
1392                {
1393                   int serv_length;
1394
1395                   serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
1396
1397                   if( i == (num_services-1) )
1398                   {
1399                      /* Last service to add */
1400                      proto_item_append_text(temp_item, "%d", serv_offset );
1401                      serv_length = item_length-add_stat_size-serv_offset-4;
1402                   }
1403                   else
1404                   {
1405                      proto_item_append_text(temp_item, "%d, ", serv_offset );
1406                      serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
1407                   }
1408
1409                   temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
1410                   temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1411                   add_cip_data( temp_tree, tvb, offset+serv_offset+4, serv_length );
1412                }
1413             } /* End if Multiple service Packet */
1414             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
1415             {
1416                /* Get Attribute List Reply (Success)*/
1417
1418                int att_count;
1419
1420                /* Add Attribute Count */
1421                att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
1422                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
1423
1424                /* Add the data */
1425                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
1426
1427             } /* End if Multiple service Packet */
1428             else
1429                         {
1430                            /* Add data */
1431                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1432                    } /* end of check service code */
1433
1434            }
1435          else
1436          {
1437             /* Error responses */
1438
1439             if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN ) ||
1440                 ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE ) )
1441             {
1442                /* Forward open and forward close error response look the same */
1443
1444                /* Display connection serial number */
1445                temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1446                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1447
1448                /* Display the originator vendor id */
1449                proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
1450
1451                /* Display the originator serial number */
1452                temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1453                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1454
1455                /* Display remaining path size */
1456                temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
1457                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
1458
1459                /* Display reserved data */
1460                temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1461                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
1462             }
1463             else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1464             {
1465                /* Unconnected send response (Unsuccess) */
1466
1467                /* Display remaining path size */
1468                temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
1469                proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
1470             }
1471             else
1472             {
1473                /* Add data */
1474                add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1475             }
1476
1477          } /* end of if-else( CI_CRC_SUCCESS ) */
1478
1479       } /* End of if command-specific data present */
1480
1481         } /* End of if reply */
1482         else
1483         {
1484            /* Request */
1485
1486            /* Add path size */
1487            req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
1488            proto_tree_add_text( item_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
1489
1490       /* Add the epath */
1491       pi = proto_tree_add_text(item_tree, tvb, offset+2, req_path_size, "Request Path: ");
1492       show_epath( tvb, pi, offset+2, req_path_size );
1493
1494       /* If there is any command specific data creat a sub-tree for it */
1495       if( (item_length-req_path_size-2) != 0 )
1496       {
1497
1498          pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
1499          cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1500
1501          /* Check what service code that recived */
1502
1503          if( tvb_get_guint8( tvb, offset ) == SC_FWD_OPEN )
1504          {
1505             /* Forward open Request*/
1506
1507             /* Display the priority/tick timer */
1508             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1509             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1510
1511             /* Display the time-out ticks */
1512             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1513             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1514
1515             /* Display the actual time out */
1516             temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1517             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1518
1519             /* Display originator to taget connection ID */
1520             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
1521             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1522
1523             /* Display target to originator connection ID */
1524             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1525             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1526
1527             /* Display connection serial number */
1528             temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
1529             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
1530
1531             /* Display the originator vendor id */
1532             proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+12, 2, TRUE);
1533
1534             /* Display the originator serial number */
1535             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
1536             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
1537
1538             /* Display the timeout multiplier */
1539             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
1540             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, enip_con_time_mult_vals , "Reserved" ), temp_data );
1541
1542             /* Put out an indicator for the reserved bytes */
1543             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
1544
1545             /* Display originator to target requested packet interval */
1546             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
1547             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 );
1548
1549               /* Display originator to target network connection patameterts, in a tree */
1550               temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
1551               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 );
1552               ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1553
1554             /* Add the data to the tree */
1555             proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
1556                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1557                         proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
1558                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1559             proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
1560                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1561                         proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
1562                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1563                         proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
1564                                         tvb, offset+2+req_path_size+26, 2, TRUE );
1565
1566             /* Display target to originator requested packet interval */
1567             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
1568             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 );
1569
1570               /* Display target to originator network connection patameterts, in a tree */
1571               temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
1572               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 );
1573               ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1574
1575             /* Add the data to the tree */
1576             proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
1577                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1578                         proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
1579                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1580             proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
1581                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1582                         proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
1583                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1584                         proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
1585                                         tvb, offset+2+req_path_size+32, 2, TRUE );
1586
1587             /* Transport type/trigger */
1588             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
1589             proto_tree_add_text( cmd_data_tree, tvb, offset+6+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
1590
1591             /* Add path size */
1592             conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
1593             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1594
1595             /* Add the epath */
1596             pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
1597             show_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size );
1598          }
1599          else if( tvb_get_guint8( tvb, offset ) == SC_FWD_CLOSE )
1600          {
1601             /* Forward Close Request */
1602
1603             /* Display the priority/tick timer */
1604             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1605             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1606
1607             /* Display the time-out ticks */
1608             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1609             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1610
1611             /* Display connection serial number */
1612             temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1613             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
1614
1615             /* Display the originator vendor id */
1616             proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+4, 2, TRUE);
1617
1618             /* Display the originator serial number */
1619             temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1620             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
1621
1622             /* Add the path size */
1623             conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
1624             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1625
1626             /* Add the reserved byte */
1627             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
1628             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
1629
1630             /* Add the EPATH */
1631             pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
1632             show_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size );
1633
1634          } /* End of forward close */
1635          else if( tvb_get_guint8( tvb, offset ) == SC_UNCON_SEND )
1636          {
1637             /* Unconnected send */
1638
1639             /* Display the priority/tick timer */
1640             temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1641             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1642
1643             /* Display the time-out ticks */
1644             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1645             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1646
1647             /* Message request size */
1648             msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1649             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
1650
1651             /* Message Request */
1652             temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
1653             temp_tree = proto_item_add_subtree(temp_item, ett_mes_req );
1654
1655             /* MR - Service */
1656             temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+4 );
1657             proto_tree_add_text( temp_tree, tvb, offset+2+req_path_size+4, 1, "Service: %s (0x%02X)", val_to_str( temp_data, encap_sc_vals , "" ), temp_data );
1658
1659             /* MR - Request path Size */
1660                    mr_req_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+5 )*2;
1661                    proto_tree_add_text( temp_tree, tvb, offset+2+req_path_size+5, 1, "Request Path Size: %d (words)", mr_req_path_size/2 );
1662
1663             /* MR - EPATH */
1664             temp_item = proto_tree_add_text(temp_tree, tvb, offset+2+req_path_size+6, mr_req_path_size, "Request Path: ");
1665             show_epath( tvb, temp_item, offset+2+req_path_size+6, mr_req_path_size );
1666
1667             /* MR - Request data */
1668             if( ( msg_req_siz-2-mr_req_path_size ) != 0 )
1669             {
1670                add_byte_array_text_to_proto_tree( temp_tree, tvb, offset+2+req_path_size+6+mr_req_path_size, msg_req_siz-2-mr_req_path_size, "Request Data: " );
1671             }
1672
1673             if( msg_req_siz % 2 )
1674             {
1675                /* Pad byte */
1676                proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
1677                   tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
1678                msg_req_siz++;   /* include the padding */
1679             }
1680
1681             /* Route Path Size */
1682             route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
1683             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 );
1684
1685             /* Reserved */
1686             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
1687                 tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
1688
1689             /* Route Path */
1690             temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path");
1691             show_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size );
1692
1693          } /* End if unconnected send */
1694          else if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
1695          {
1696             /* Multiple service packet */
1697
1698             /* Add number of services */
1699             num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
1700             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
1701
1702             /* Add services */
1703             temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
1704
1705             for( i=0; i < num_services; i++ )
1706             {
1707                int serv_length;
1708
1709                serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
1710
1711                if( i == (num_services-1) )
1712                {
1713                   /* Last service to add */
1714                   serv_length = item_length-2-req_path_size-serv_offset;
1715                   proto_item_append_text(temp_item, "%d", serv_offset );
1716                }
1717                else
1718                {
1719                   serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
1720                   proto_item_append_text(temp_item, "%d, ", serv_offset );
1721                }
1722
1723                temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
1724                temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1725                add_cip_data( temp_tree, tvb, offset+serv_offset+6, serv_length );
1726             }
1727          } /* End if Multiple service Packet */
1728          else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
1729          {
1730             /* Get attribute list request */
1731
1732             int att_count;
1733
1734             /* Add number of services */
1735             att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
1736             proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
1737
1738             /* Add Attribute List */
1739             temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
1740
1741             for( i=0; i < att_count; i++ )
1742             {
1743                if( i == (att_count-1) )
1744                   proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1745                else
1746                   proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1747             }
1748
1749          } /* End of Get attribute list request */
1750          else
1751          {
1752                       /* Add data */
1753             add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
1754          } /* End of check service code */
1755
1756       } /* End of if command-specific data present */
1757
1758         } /* end of if-else( request ) */
1759
1760 } /* end of add_cip_data() */
1761
1762
1763
1764 static void
1765 show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
1766 {
1767    proto_item *temp_item, *ri, *ci;
1768    proto_item *sockaddr_item;
1769         proto_tree *temp_tree, *cip_tree, *item_tree, *sockaddr_tree;
1770         int temp_data, item_count, item_length, item, i;
1771         char temp_char;
1772         unsigned char name_length;
1773
1774         /* Show Common Data Format sub tree */
1775         item_count = tvb_get_letohs( tvb, offset );
1776    ri = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
1777         cip_tree = proto_item_add_subtree(ri, ett_cip);
1778
1779         while( item_count-- )
1780         {
1781                 /* Add item type tree */
1782                 ci = proto_tree_add_item(cip_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
1783                 item_tree = proto_item_add_subtree(ci, ett_cpf);
1784
1785                 /* Add length field */
1786       temp_data = tvb_get_letohs( tvb, offset+4 );
1787       proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", temp_data );
1788
1789                 item        = tvb_get_letohs( tvb, offset+2 );
1790                 item_length = tvb_get_letohs( tvb, offset+4 );
1791
1792                 if( item_length )
1793                 {
1794                    /* Add item data field */
1795
1796                         switch( item )
1797                         {
1798                            case CONNECTION_BASED:
1799
1800                               /* Add Connection identifier */
1801                               proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%04X", tvb_get_letohl( tvb, offset + 6 )  );
1802                               break;
1803
1804                            case UNCONNECTED_MSG:
1805
1806                                         /* Add CIP data tree*/
1807                                         add_cip_data( item_tree, tvb, offset+6, item_length );
1808
1809                                         break;
1810
1811             case CONNECTION_TRANSPORT:
1812
1813                if( encap_service == SEND_UNIT_DATA )
1814                {
1815                   /*
1816                   ** If the encapsulation service is SendUnit Data, this is a
1817                   ** encapsulated connected message
1818                   */
1819
1820                   /* Add sequence count ( Transport Class 1,2,3 )*/
1821                   proto_tree_add_text( item_tree, tvb, offset+6, 2, "Sequence Count: 0x%04X", tvb_get_letohs( tvb, offset+6 ) );
1822
1823                   /* Add CIP data tree */
1824                   add_cip_data( item_tree, tvb, offset+8, item_length-2 );
1825                }
1826                else
1827                {
1828                   /* Display data */
1829                   add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
1830
1831                } /* End of if send unit data */
1832
1833                break;
1834
1835
1836             case LIST_IDENTITY_RESP:
1837
1838                /* Encapsulation version */
1839                temp_data = tvb_get_letohs( tvb, offset+6 );
1840                proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
1841
1842                /* Socket Address */
1843                sockaddr_item = proto_tree_add_text( item_tree, tvb, offset+8, 16, "Socket Address");
1844                sockaddr_tree = proto_item_add_subtree( sockaddr_item, ett_sockadd );
1845
1846                /* Socket address struct - sin_family */
1847                proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinfamily,
1848                                                         tvb, offset+8, 2, FALSE );
1849
1850                /* Socket address struct - sin_port */
1851                proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinport,
1852                                                         tvb, offset+10, 2, FALSE );
1853
1854                /* Socket address struct - sin_address */
1855                proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinaddr,
1856                                                         tvb, offset+12, 4, FALSE );
1857
1858                /* Socket address struct - sin_zero */
1859                proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinzero,
1860                                                         tvb, offset+16, 8, FALSE );
1861
1862                /* Vendor ID */
1863                proto_tree_add_item(item_tree, hf_enip_vendors,
1864                                                         tvb, offset+24, 2, TRUE );
1865
1866                /* Device Type */
1867                proto_tree_add_item(item_tree, hf_enip_cpf_lir_devtype,
1868                                                         tvb, offset+26, 2, TRUE );
1869
1870                /* Product Code */
1871                proto_tree_add_item(item_tree, hf_enip_cpf_lir_prodcode,
1872                                                         tvb, offset+28, 2, TRUE );
1873
1874                /* Revision */
1875                temp_data = tvb_get_letohs( tvb, offset+30 );
1876                proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: v.%d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
1877
1878                /* Status */
1879                proto_tree_add_item(item_tree, hf_enip_cpf_lir_status,
1880                                                         tvb, offset+32, 2, TRUE );
1881
1882                /* Serial Number */
1883                proto_tree_add_item(item_tree, hf_enip_cpf_lir_sernbr,
1884                                                         tvb, offset+34, 4, TRUE );
1885
1886                /* Product Name Length */
1887                proto_tree_add_item(item_tree, hf_enip_cpf_lir_namelength,
1888                                                         tvb, offset+38, 1, TRUE );
1889
1890                /* Get the lenth of the name */
1891                name_length = tvb_get_guint8( tvb, offset+38 );
1892
1893                /* Product Name Length */
1894                proto_tree_add_item(item_tree, hf_enip_cpf_lir_name,
1895                                                         tvb, offset+39, name_length, TRUE );
1896
1897                /* Product Name Length */
1898                proto_tree_add_item(item_tree, hf_enip_cpf_lir_state,
1899                                                         tvb, offset+name_length+39, 1, TRUE );
1900                break;
1901
1902
1903             case SOCK_ADR_INFO_OT:
1904             case SOCK_ADR_INFO_TO:
1905
1906                /* Socket address struct - sin_family */
1907                proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinfamily,
1908                                                         tvb, offset+6, 2, FALSE );
1909
1910                /* Socket address struct - sin_port */
1911                proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinport,
1912                                                         tvb, offset+8, 2, FALSE );
1913
1914                /* Socket address struct - sin_address */
1915                proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinaddr,
1916                                                         tvb, offset+10, 4, FALSE );
1917
1918                /* Socket address struct - sin_zero */
1919                proto_tree_add_item( item_tree, hf_enip_cpf_lir_sinzero,
1920                                                         tvb, offset+14, 8, FALSE );
1921                                    break;
1922
1923
1924             case SEQ_ADDRESS:
1925                proto_tree_add_item(item_tree, hf_enip_cpf_sat_connid,
1926                                                         tvb, offset+6, 4, TRUE );
1927
1928                proto_tree_add_item(item_tree, hf_enip_cpf_sat_seqnum,
1929                                                         tvb, offset+10, 4, TRUE );
1930
1931                /* Add info to column */
1932
1933                if(check_col(pinfo->cinfo, COL_INFO))
1934                     {
1935                        col_clear(pinfo->cinfo, COL_INFO);
1936
1937                   col_add_fstr(pinfo->cinfo, COL_INFO,
1938                                          "Connection: ID=0x%08X, SEQ=%010d",
1939                                          tvb_get_letohl( tvb, offset+6 ),
1940                                          tvb_get_letohl( tvb, offset+10 ) );
1941                                    }
1942
1943                                    break;
1944
1945             case LIST_SERVICES_RESP:
1946
1947                /* Encapsulation version */
1948                temp_data = tvb_get_letohs( tvb, offset+6 );
1949                proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
1950
1951                /* Capability flags */
1952                temp_data = tvb_get_letohs( tvb, offset+8 );
1953                temp_item = proto_tree_add_text(item_tree, tvb, offset+8, 2, "Capability Flags: 0x%04X", temp_data );
1954                temp_tree = proto_item_add_subtree(temp_item, ett_lsrcf);
1955
1956                proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_tcp,
1957                   tvb, offset+8, 2, TRUE );
1958                    proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_udp,
1959                            tvb, offset+8, 2, TRUE );
1960
1961                /* Name of service */
1962                temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name Of Service: " );
1963
1964                for( i=0; i<16; i++ )
1965                {
1966                     temp_char = tvb_get_guint8( tvb, offset+10+i );
1967
1968                     if( temp_char == 0 )
1969                      break;
1970
1971                     proto_item_append_text(temp_item, "%c", temp_char );
1972                }
1973                break;
1974
1975
1976                                 default:
1977
1978                add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
1979                break;
1980
1981                         } /* end of switch( item type ) */
1982
1983                 } /* end of if( item length ) */
1984
1985                 offset = offset + item_length + 4;
1986
1987         } /* end of while( item count ) */
1988
1989 } /* end of show_cdf() */
1990
1991
1992
1993 static int
1994 classify_packet(packet_info *pinfo)
1995 {
1996         /* see if nature of packets can be derived from src/dst ports */
1997         /* if so, return as found */
1998         if ( ( ENIP_ENCAP_PORT == pinfo->srcport && ENIP_ENCAP_PORT != pinfo->destport ) ||
1999                  ( ENIP_ENCAP_PORT != pinfo->srcport && ENIP_ENCAP_PORT == pinfo->destport ) ) {
2000                 if ( ENIP_ENCAP_PORT == pinfo->srcport )
2001                         return RESPONSE_PACKET;
2002                 else if ( ENIP_ENCAP_PORT == pinfo->destport )
2003                         return REQUEST_PACKET;
2004         }
2005         /* else, cannot classify */
2006         return CANNOT_CLASSIFY;
2007 }
2008
2009
2010
2011 /* Code to actually dissect the packets */
2012 static int
2013 dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2014 {
2015    int      packet_type;
2016    guint16  encap_cmd, encap_data_length;
2017    gchar    *cmd_string;
2018    char     pkt_type_str[9] = "";
2019    guint32  status;
2020
2021    /* Set up structures needed to add the protocol subtree and manage it */
2022    proto_item *ti, *encaph, *csf;
2023    proto_tree *cipencap_tree, *headertree, *csftree;
2024
2025    /* An ENIP packet is at least 4 bytes long - we need the command type. */
2026    if (!tvb_bytes_exist(tvb, 0, 4))
2027       return 0;
2028
2029    /* Get the command type and see if it's valid. */
2030    encap_cmd = tvb_get_letohs( tvb, 0 );
2031    cmd_string = match_strval(encap_cmd, encap_cmd_vals);
2032    if (cmd_string == NULL)
2033       return 0; /* not a known command */
2034
2035    /* Make entries in Protocol column and Info column on summary display */
2036    if (check_col(pinfo->cinfo, COL_PROTOCOL))
2037       col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
2038
2039    if(check_col(pinfo->cinfo, COL_INFO))
2040    {
2041       packet_type = classify_packet(pinfo);
2042
2043       switch ( packet_type )
2044       {
2045          case REQUEST_PACKET:
2046             strcpy(pkt_type_str, "Request");
2047             break;
2048
2049          case RESPONSE_PACKET:
2050             strcpy(pkt_type_str, "Response");
2051             break;
2052
2053          default:
2054             strcpy(pkt_type_str, "Unknown");
2055       }
2056
2057       col_add_fstr(pinfo->cinfo, COL_INFO,
2058                    "%s: %s, Session=0x%08X",
2059                    pkt_type_str, cmd_string, tvb_get_letohl( tvb, 4 ) );
2060    } /* end of if( col exists ) */
2061
2062    /* In the interest of speed, if "tree" is NULL, don't do any work not
2063       necessary to generate protocol tree items. */
2064    if (tree) {
2065
2066       /* create display subtree for the protocol */
2067       ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
2068
2069       cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
2070
2071       /* Add encapsulation header tree */
2072       encaph     = proto_tree_add_text( cipencap_tree, tvb, 0, 24, "Encapsulation Header");
2073       headertree = proto_item_add_subtree(encaph, ett_cipencaph);
2074
2075       /* CIP header information */
2076       proto_tree_add_uint(headertree, hf_enip_command, tvb, 0, 2, encap_cmd);
2077
2078       encap_data_length = tvb_get_letohs( tvb, 2 );
2079       proto_tree_add_text( headertree, tvb, 2, 2, "Length: %u", encap_data_length );
2080
2081       proto_tree_add_text( headertree, tvb, 4, 4, "Session Handle: 0x%08X",
2082                           tvb_get_letohl( tvb, 4 ) );
2083
2084       status = tvb_get_letohl( tvb, 8 );
2085       proto_tree_add_text( headertree, tvb, 8, 4, "Status: %s (0x%08X)",
2086                           val_to_str( status, encap_status_vals,
2087                                      "Unknown Status Code" ),
2088                           status);
2089
2090       add_byte_array_text_to_proto_tree( headertree, tvb, 12, 8, "Sender context: " );
2091
2092       proto_tree_add_text( headertree, tvb, 20, 4, "Options: 0x%08X",
2093                           tvb_get_letohl( tvb, 20 ) );
2094
2095       /* Command specific data - create tree */
2096       if( encap_data_length )
2097       {
2098          /* The packet have some command specific data, buid a sub tree for it */
2099
2100          csf = proto_tree_add_text( cipencap_tree, tvb, 24, encap_data_length,
2101                                    "Command Specific Data");
2102
2103          csftree = proto_item_add_subtree(csf, ett_csf);
2104
2105          switch( encap_cmd )
2106          {
2107             case NOP:
2108                show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2109                break;
2110
2111             case LIST_SERVICES:
2112                show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2113                break;
2114
2115             case LIST_IDENTITY:
2116                show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2117                break;
2118
2119             case LIST_INTERFACES:
2120                show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2121                break;
2122
2123             case REGISTER_SESSION:
2124                proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X",
2125                                    tvb_get_letohs( tvb, 24 ) );
2126
2127                proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X",
2128                                    tvb_get_letohs( tvb, 26 ) );
2129
2130                break;
2131
2132             case UNREGISTER_SESSION:
2133                break;
2134
2135             case SEND_RR_DATA:
2136             case SEND_UNIT_DATA:
2137                proto_tree_add_item(csftree, hf_enip_ifacehnd, tvb, 24, 4, TRUE);
2138
2139                proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
2140                                    tvb_get_letohs( tvb, 28 ) );
2141
2142                show_cdf( encap_cmd, tvb, pinfo, csftree, 30 );
2143                break;
2144
2145             case INDICATE_STATUS:
2146             case CANCEL:
2147             default:
2148
2149                /* Can not decode - Just show the data */
2150                add_byte_array_text_to_proto_tree( headertree, tvb, 24, encap_data_length, "Encap Data: " );
2151                break;
2152
2153          } /* end of switch() */
2154
2155       } /* end of if( encapsulated data ) */
2156
2157    }
2158
2159    return tvb_length(tvb);
2160 } /* end of dissect_cipencap() */
2161
2162
2163 /* Code to actually dissect the io packets*/
2164 static void
2165 dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2166 {
2167    /* Set up structures needed to add the protocol subtree and manage it */
2168         proto_item *ti;
2169         proto_tree *cipencap_tree;
2170
2171    /* Make entries in Protocol column and Info column on summary display */
2172         if (check_col(pinfo->cinfo, COL_PROTOCOL))
2173                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
2174
2175    /* In the interest of speed, if "tree" is NULL, don't do any work not
2176    necessary to generate protocol tree items. */
2177         if (tree)
2178         {
2179       /* create display subtree for the protocol */
2180                 ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
2181
2182                 cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
2183
2184       show_cdf( 0xFFFF, tvb, pinfo, cipencap_tree, 0 );
2185         }
2186
2187 } /* end of dissect_enipio() */
2188
2189
2190 /* Register the protocol with Ethereal */
2191
2192 /* this format is require because a script is used to build the C function
2193    that calls all the protocol registration.
2194 */
2195
2196 void
2197 proto_register_cipencap(void)
2198 {
2199
2200 /* Setup list of header fields  lengthSee Section 1.6.1 for details*/
2201         static hf_register_info hf[] = {
2202                 { &hf_enip_command,
2203                         { "Command",           "enip.command",
2204                         FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
2205                         "Encapsulation command", HFILL }
2206                 },
2207
2208                 /* Encapsulated data headers */
2209                 /* Common Packet Format */
2210                 { &hf_enip_cpf_typeid,
2211                         { "Type ID",          "enip.cpf.typeid",
2212                         FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
2213                         "Type of encapsulated item", HFILL }
2214                 },
2215
2216                 /* Send RR Data */
2217                 { &hf_enip_ifacehnd,
2218                         { "Interface Handle",           "enip.cpf.rr.ifacehnd",
2219                         FT_UINT32, BASE_HEX, NULL, 0,
2220                         "Interface handle", HFILL }
2221                 },
2222
2223                 /* Unconnected message */
2224       { &hf_enip_ucm_rr,
2225                         { "Request/Response", "enip.cip.rr",
2226                         FT_UINT8, BASE_HEX, VALS(encap_sc_rr), 0x80,
2227                         "Request or Response message", HFILL }
2228                 },
2229                 { &hf_enip_ucm_sc,
2230                         { "Service",           "enip.cip.sc",
2231                         FT_UINT8, BASE_HEX, VALS(encap_sc_vals), 0x7F,
2232                         "CIP Service code", HFILL }
2233                 },
2234                 { &hf_enip_ucm_path,
2235                         { "Request Path",           "enip.cip.path",
2236                         FT_BYTES, BASE_HEX, NULL, 0,
2237                         "Request path", HFILL }
2238                 },
2239                 { &hf_enip_ucm_genstat,
2240                         { "General Status",           "enip.cip.genstat",
2241                         FT_UINT8, BASE_HEX, VALS(encap_cip_gs_vals), 0,
2242                         "General Status", HFILL }
2243                 },
2244
2245                 /* List identity response */
2246       { &hf_enip_cpf_lir_sinfamily,
2247                         { "sin_family", "enip.lir.sinfamily",
2248                         FT_UINT16, BASE_DEC, NULL, 0,
2249                         "Socket Address Sin Family", HFILL }
2250                 },
2251       { &hf_enip_cpf_lir_sinport,
2252                         { "sin_port", "enip.lir.sinport",
2253                         FT_UINT16, BASE_DEC, NULL, 0,
2254                         "Socket Address Sin Port", HFILL }
2255                 },
2256       { &hf_enip_cpf_lir_sinaddr,
2257                         { "sin_addr", "enip.lir.sinaddr",
2258                         FT_IPv4, BASE_HEX, NULL, 0,
2259                         "Socket Address Sin Addr", HFILL }
2260                 },
2261       { &hf_enip_cpf_lir_sinzero,
2262                         { "sin_zero", "enip.lir.sinzero",
2263                         FT_BYTES, BASE_HEX, NULL, 0,
2264                         "Socket Address Sin Zero", HFILL }
2265                 },
2266       { &hf_enip_cpf_lir_devtype,
2267                         { "Device Type", "enip.lir.devtype",
2268                         FT_UINT16, BASE_DEC, VALS(encap_cip_devtype_vals), 0,
2269                         "Device Type", HFILL }
2270                 },
2271       { &hf_enip_cpf_lir_prodcode,
2272                         { "Product Code", "enip.lir.prodcode",
2273                         FT_UINT16, BASE_DEC, NULL, 0,
2274                         "Product Code", HFILL }
2275                 },
2276       { &hf_enip_cpf_lir_status,
2277                         { "Status", "enip.lir.status",
2278                         FT_UINT16, BASE_HEX, NULL, 0,
2279                         "Status", HFILL }
2280                 },
2281       { &hf_enip_cpf_lir_sernbr,
2282                         { "Serial Number", "enip.lir.ser",
2283                         FT_UINT32, BASE_HEX, NULL, 0,
2284                         "Serial Number", HFILL }
2285                 },
2286       { &hf_enip_cpf_lir_namelength,
2287                         { "Product Name Length", "enip.lir.namelength",
2288                         FT_UINT8, BASE_DEC, NULL, 0,
2289                         "Product Name Length", HFILL }
2290                 },
2291       { &hf_enip_cpf_lir_name,
2292                         { "Product Name", "enip.lir.name",
2293                         FT_STRING, BASE_NONE, NULL, 0,
2294                         "Product Name", HFILL }
2295                 },
2296       { &hf_enip_cpf_lir_state,
2297                         { "State", "enip.lir.state",
2298                         FT_UINT8, BASE_HEX, NULL, 0,
2299                         "State", HFILL }
2300                 },
2301       /* Vendor ID number */
2302                 { &hf_enip_vendors,
2303                         { "Vendor ID",           "enip.vnd",
2304                         FT_UINT16, BASE_HEX, VALS(encap_cip_vendor_vals), 0,
2305                         "Vendor ID number", HFILL }
2306                 },
2307       { &hf_enip_ucm_fwo_comp,
2308                         { "Compatibility", "enip.cip.fwo.cmp",
2309                         FT_UINT8, BASE_HEX, VALS(enip_com_bit_vals), 0x80,
2310                         "Compatibility bit", HFILL }
2311                 },
2312       { &hf_enip_ucm_fwo_mrev,
2313                         { "Major Revision", "enip.cip.fwo.mrev",
2314                         FT_UINT8, BASE_DEC, NULL, 0x7F,
2315                         "Major Revision", HFILL }
2316                 },
2317       { &hf_enip_ucm_fwo_con_size,
2318                         { "Connection Size", "enip.cip.fwo.consize",
2319                         FT_UINT16, BASE_DEC, NULL, 0x01FF,
2320                         "Connection size", HFILL }
2321                 },
2322       { &hf_enip_ucm_fwo_fixed_var,
2323                         { "Connection Size Type", "enip.cip.fwo.f_v",
2324                         FT_UINT16, BASE_DEC, VALS(enip_con_fw_vals), 0x0200,
2325                         "Fixed or variable connection size", HFILL }
2326                 },
2327       { &hf_enip_ucm_fwo_prio,
2328                         { "Priority", "enip.cip.fwo.prio",
2329                         FT_UINT16, BASE_DEC, VALS(enip_con_prio_vals), 0x0C00,
2330                         "Connection priority", HFILL }
2331                 },
2332       { &hf_enip_ucm_fwo_typ,
2333                         { "Connection Type", "enip.cip.fwo.typ",
2334                         FT_UINT16, BASE_DEC, VALS(enip_con_type_vals), 0x6000,
2335                         "Connection type", HFILL }
2336                 },
2337       { &hf_enip_ucm_fwo_own,
2338                         { "Owner", "enip.cip.fwo.own",
2339                         FT_UINT16, BASE_DEC, VALS(enip_con_owner_vals), 0x8000,
2340                         "Redundant owner bit", HFILL }
2341                 },
2342                 /* Sequenced Address Type */
2343       { &hf_enip_cpf_sat_connid,
2344                         { "Connection ID", "enip.sat.connid",
2345                         FT_UINT32, BASE_HEX, NULL, 0,
2346                         "Connection ID from forward open reply", HFILL }
2347                 },
2348       { &hf_enip_cpf_sat_seqnum,
2349                         { "Sequence Number", "enip.sat.seq",
2350                         FT_UINT32, BASE_DEC, NULL, 0,
2351                         "Sequence Number", HFILL }
2352                 },
2353                 { &hf_enip_cpf_lsr_tcp,
2354                         { "Supports CIP Encapsultion via TCP", "enip.ls.tcp",
2355                         FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
2356                         "Supports CIP Encapsultion via TCP", HFILL }
2357                 },
2358                 { &hf_enip_cpf_lsr_udp,
2359                         { "Supports CIP Class 0 or 1 via UDP", "enip.ls.udp",
2360                         FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
2361                         "Supports CIP Class 0 or 1 via UDP", HFILL }
2362                 }
2363
2364    };
2365
2366
2367 /* Setup protocol subtree array */
2368         static gint *ett[] = {
2369                 &ett_cipencap,
2370                 &ett_cip,
2371                 &ett_cpf,
2372                 &ett_path,
2373                 &ett_ekey_path,
2374                 &ett_cipencaph,
2375                 &ett_csf,
2376                 &ett_rrsc,
2377                 &ett_sockadd,
2378                 &ett_mcsc,
2379                 &ett_ncp,
2380                 &ett_cia_path,
2381                 &ett_data_seg,
2382                 &ett_lsrcf,
2383                 &ett_mes_req,
2384                 &ett_cmd_data,
2385                 &ett_port_path,
2386                 &ett_mult_ser
2387         };
2388
2389 /* Register the protocol name and description */
2390         proto_cipencap = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
2391             "ENIP", "enip");
2392
2393 /* Required function calls to register the header fields and subtrees used */
2394         proto_register_field_array(proto_cipencap, hf, array_length(hf));
2395         proto_register_subtree_array(ett, array_length(ett));
2396
2397 } /* end of proto_register_cipencap() */
2398
2399
2400 /* If this dissector uses sub-dissector registration add a registration routine.
2401    This format is required because a script is used to find these routines and
2402    create the code that calls these routines.
2403 */
2404 void
2405 proto_reg_handoff_cipencap(void)
2406 {
2407         dissector_handle_t cipencap_handle;
2408         dissector_handle_t enipio_handle;
2409
2410         /* Register for encapsulated CIP data, using both TCP/UDP */
2411         cipencap_handle = new_create_dissector_handle(dissect_cipencap, proto_cipencap);
2412         dissector_add("tcp.port", ENIP_ENCAP_PORT, cipencap_handle);
2413         dissector_add("udp.port", ENIP_ENCAP_PORT, cipencap_handle);
2414
2415         /* Register for IO data over UDP */
2416         enipio_handle = create_dissector_handle(dissect_enipio, proto_cipencap);
2417         dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
2418
2419 } /* end of proto_reg_handoff_cipencap() */