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