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