2 * Routines for EtherNet/IP (Industrial Protocol) dissection
3 * EtherNet/IP Home: www.odva.org
6 * Magnus Hansson <mah@hms.se>
7 * Joakim Wiberg <jow@hms.se>
9 * $Id: packet-enip.c,v 1.10 2004/02/25 09:31:05 guy Exp $
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
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.
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.
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.
40 #ifdef NEED_SNPRINTF_H
41 # include "snprintf.h"
44 #include <epan/packet.h>
46 #include "packet-tcp.h"
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 */
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
57 /* CIP Encapsulation function codes */
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
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
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
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
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
106 #define SC_NO_OP 0x17
107 #define SC_GET_MEMBER 0x18
108 #define SC_SET_MEMBER 0x19
110 #define SC_FWD_CLOSE 0x4E
111 #define SC_UNCON_SEND 0x52
112 #define SC_FWD_OPEN 0x54
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
158 #define CI_GRC_STILL_PROCESSING 0xFF
162 #define CI_SEGMENT_TYPE_MASK 0xE0
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
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
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
187 #define CI_E_KEY_FORMAT_VAL 0x04
189 #define CI_DATA_SEG_SIMPLE 0x80
190 #define CI_DATA_SEG_SYMBOL 0x91
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
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
214 #define DP_MASS_FLOW_CNT 0x1A
215 #define DP_PNEUM_VALVE 0x1B
216 #define DP_VACUUM_PRES_GAUGE 0x1C
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;
225 static int hf_enip_cpf_typeid = -1;
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;
243 static int hf_enip_cpf_sat_connid = -1;
244 static int hf_enip_cpf_sat_seqnum = -1;
246 static int hf_enip_vendors = -1;
248 static int hf_enip_ucm_fwo_comp = -1;
249 static int hf_enip_ucm_fwo_mrev = -1;
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;
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;
261 static int hf_enip_cpf_lsr_tcp = -1;
262 static int hf_enip_cpf_lsr_udp = -1;
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;
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;
286 static gboolean cipencap_desegment = TRUE;
288 /* Translate function to string - Encapsulation commands */
289 static const value_string encap_cmd_vals[] = {
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" },
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" },
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" },
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" },
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" },
351 { SC_GET_MEMBER, "Get Member" },
352 { SC_SET_MEMBER, "Set Member" },
353 { SC_MULT_SERV_PACK, "Multiple Service Packet" },
355 /* Some class specific services */
356 { SC_FWD_CLOSE, "Forward Close" },
357 { SC_FWD_OPEN, "Forward Open" },
358 { SC_UNCON_SEND, "Unconnected Send" },
363 /* Translate function to string - CIP Request/Response */
364 static const value_string encap_sc_rr[] = {
372 /* Translate function to string - Compatibility */
373 static const value_string enip_com_bit_vals[] = {
374 { 0, "Bit Cleared" },
380 /* Translate function to string - True/False */
381 static const value_string enip_true_false_vals[] = {
389 /* Translate function to string - Connection priority */
390 static const value_string enip_con_prio_vals[] = {
391 { 0, "Low Priority" },
392 { 1, "High Priority" },
400 /* Translate function to string - Connection size fixed or variable */
401 static const value_string enip_con_fw_vals[] = {
409 /* Translate function to string - Connection owner */
410 static const value_string enip_con_owner_vals[] = {
417 /* Translate function to string - Connection direction */
418 static const value_string enip_con_dir_vals[] = {
425 /* Translate function to string - Production trigger */
426 static const value_string enip_con_trigg_vals[] = {
428 { 1, "Change-Of-State" },
429 { 2, "Application Object" },
434 /* Translate function to string - Transport class */
435 static const value_string enip_con_class_vals[] = {
445 /* Translate function to string - Connection type */
446 static const value_string enip_con_type_vals[] = {
449 { 2, "Point to Point" },
455 /* Translate function to string - Timeout Multiplier */
456 static const value_string enip_con_time_mult_vals[] = {
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" },
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." },
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." },
574 { 859, "Tennessee Rand Automation" },
575 { 866, "ATR Industrie-Elektronik GmbH Co." },
576 { 875, "FieldServer Technologies (Div Sierra Monitor Corp)" },
577 { 883, "Automa SRL" },
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" },
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" },
662 add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
665 char *tmp2, *tmp2start;
667 int i,tmp_length,tmp2_length;
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' };
680 if( ( length * 2 ) > 32 )
688 tmp2_length = ( length * 2 ) + 1;
691 tmp = tvb_get_ptr( tvb, start, tmp_length );
692 tmp2 = (char*)g_malloc( tmp2_length );
696 for( i = 0; i < tmp_length; i++ )
700 *tmp2++ = my_hex_digits[octet&0xF];
702 *tmp2++ = my_hex_digits[octet&0xF];
705 if( tmp_length != length )
714 pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
720 } /* end of add_byte_array_text_to_proto_tree() */
724 /* Decode and add epath to tree */
726 show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
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;
737 int seg_size, i, temp_word;
740 /* Create a sub tree for the epath */
741 path_tree = proto_item_add_subtree( pi, ett_path );
743 proto_tree_add_item_hidden(path_tree, hf_enip_ucm_path,
744 tvb, offset, path_length, TRUE );
748 while( pathpos < path_length )
750 /* Get segement type */
751 segment_type = tvb_get_guint8( tvb, offset + pathpos );
753 /* Determine the segment type */
755 switch( segment_type & CI_SEGMENT_TYPE_MASK )
757 case CI_PATH_SEGMENT:
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 );
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) );
766 /* Add Extended Link Address flag */
767 temp_item = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: " );
769 if( segment_type & 0x10 )
771 proto_item_append_text(temp_item, "TRUE");
772 opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
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: " );
777 proto_item_append_text(pi, ", Addess: " );
779 /* Add extended link address */
780 for( i=0; i < opt_link_size; i++ )
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 );
788 if( opt_link_size % 2 )
790 pathpos = pathpos + 3 + opt_link_size;
791 proto_item_set_len(port_item, 3+opt_link_size);
795 pathpos = pathpos + 2 + opt_link_size;
796 proto_item_set_len(port_item, 2+opt_link_size);
802 proto_item_append_text(pi, ", Address: %d", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
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);
812 case CI_LOGICAL_SEGMENT:
814 /* Logical segment, determin the logical type */
816 switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
818 case CI_LOGICAL_SEG_CLASS_ID:
820 /* Logical Class ID, do a format check */
822 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
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 );
827 /* Create a sub tree for the class */
828 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
833 temp_string = match_strval( temp_data, enip_class_names_vals );
837 proto_item_append_text(pi, "%s", temp_string );
841 proto_item_append_text(pi, "Class: 0x%02X", temp_data );
844 /* 2 bytes of path used */
847 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
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 );
852 /* Create a sub tree for the class */
853 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
861 proto_item_append_text(pi, "%s", temp_string );
865 proto_item_append_text(pi, "Class: 0x%04X", temp_data );
868 /* 4 bytes of path used */
871 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
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 );
876 /* Create a sub tree for the class */
877 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
885 proto_item_append_text(pi, "%s", temp_string );
889 proto_item_append_text(pi, "Class: 0x%08X", temp_data );
892 /* 6 bytes of path used */
897 /* Unsupported logical segment format */
898 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
904 case CI_LOGICAL_SEG_INST_ID:
906 /* Logical Instance ID, do a format check */
908 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
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 );
913 /* Create a sub tree for the instance */
914 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
920 /* 2 bytes of path used */
923 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
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 );
928 /* Create a sub tree for the instance */
929 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
935 /* 4 bytes of path used */
938 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
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 );
943 /* Create a sub tree for the instance */
944 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
950 /* 6 bytes of path used */
955 /* Unsupported logical segment format */
956 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
962 case CI_LOGICAL_SEG_ATTR_ID:
964 /* Logical Attribute ID, do a format check */
966 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
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 );
971 /* Create a sub tree for the attribute */
972 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
978 /* 2 bytes of path used */
981 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
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 );
986 /* Create a sub tree for the attribute */
987 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
993 /* 4 bytes of path used */
996 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
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 );
1001 /* Create a sub tree for the attribute */
1002 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
1008 /* 6 bytes of path used */
1013 /* Unsupported logical segment format */
1014 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
1020 case CI_LOGICAL_SEG_CON_POINT:
1022 /* Logical Connection point , do a format check */
1024 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
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 );
1029 /* Create a sub tree for the connection point */
1030 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
1036 /* 2 bytes of path used */
1039 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
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 );
1044 /* Create a sub tree for the connection point */
1045 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
1051 /* 4 bytes of path used */
1054 else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
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 );
1059 /* Create a sub tree for the connection point */
1060 cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
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 );
1066 /* 6 bytes of path used */
1071 /* Unsupported logical segment format */
1072 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
1078 case CI_LOGICAL_SEG_SPECIAL:
1080 /* Logical Special ID, the only logical format sepcifyed is electronic key */
1082 if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
1085 /* Get the Key Format */
1087 temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
1089 if( temp_data == CI_E_KEY_FORMAT_VAL )
1091 qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
1093 /* Create a sub tree for the IOI */
1094 e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
1096 /* Print the key type */
1097 proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
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 );
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 );
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 );
1113 /* Major revision/Compatibility */
1114 temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
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);
1120 /* Add Compatibility bit info */
1121 proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_comp,
1122 tvb, offset + pathpos + 8, 1, TRUE );
1124 proto_item_append_text( mcpi, "%s, Major Revision: %d",
1125 val_to_str( ( temp_data & 0x80 )>>7, enip_com_bit_vals , "" ),
1128 /* Major revision */
1129 proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_mrev,
1130 tvb, offset + pathpos + 8, 1, TRUE );
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 );
1136 proto_item_append_text( qi, ", V.%d.%d", ( temp_data & 0x7F ), temp_data2 );
1138 /* Increment the path pointer */
1144 /* Unsupported electronic key format */
1145 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
1152 /* Unsupported special segment format */
1153 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
1161 /* Unsupported logical segment type */
1162 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
1165 } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
1169 case CI_DATA_SEGMENT:
1171 /* Data segment, determin the logical type */
1173 switch( segment_type )
1176 case CI_DATA_SEG_SIMPLE:
1178 /* Simple data segment */
1179 ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
1181 /* Create a sub tree */
1182 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
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 );
1191 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
1193 for( i=0; i < seg_size/2; i ++ )
1195 temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
1196 proto_item_append_text(qi, " 0x%04X", temp_word );
1199 proto_item_set_len(qi, seg_size);
1202 proto_item_set_len( ds_item, 2 + seg_size );
1203 pathpos = pathpos + 2 + seg_size;
1207 case CI_DATA_SEG_SYMBOL:
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 );
1212 /* Create a sub tree */
1213 ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
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 );
1222 qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
1224 for( i=0; i < seg_size; i++ )
1226 temp_byte = tvb_get_guint8( tvb, offset + pathpos+2+i );
1227 proto_item_append_text(qi, "%c", temp_byte );
1230 proto_item_set_len(qi, seg_size);
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 ) );
1242 proto_item_set_len( ds_item, 2 + seg_size );
1243 pathpos = pathpos + 2 + seg_size;
1248 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
1251 } /* End of switch sub-type */
1255 case CI_NETWORK_SEGMENT:
1257 /* Network segment -Determine the segment sub-type */
1259 switch( segment_type & CI_NETWORK_SEG_TYPE_MASK )
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 );
1265 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Multiplier/Phase: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
1267 /* 2 bytes of path used */
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 );
1275 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Fixed Tag: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
1277 /* 2 bytes of path used */
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 );
1285 proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Production Inhibit Time: %dms", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
1287 /* 2 bytes of path used */
1292 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
1295 } /* End of switch sub-type */
1301 /* Unsupported segment type */
1302 proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
1305 } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
1307 } /* end of while( pathpos < path_length ) */
1309 } /* end of show_epath() */
1314 add_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
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;
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;
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);
1334 /* Add Request/Response */
1335 proto_tree_add_item(rrsci_tree, hf_enip_ucm_rr,
1336 tvb, offset, 1, TRUE );
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,
1346 /* Add service to info column */
1347 if(check_col(pinfo->cinfo, COL_INFO))
1349 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
1350 val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
1351 encap_sc_vals , "Unknown Service (%x)") );
1355 /* Add Service code */
1356 proto_tree_add_item(rrsci_tree, hf_enip_ucm_sc,
1357 tvb, offset, 1, TRUE );
1360 if( tvb_get_guint8( tvb, offset ) & 0x80 )
1362 /* Response message */
1364 /* Add general status */
1365 gen_stat = tvb_get_guint8( tvb, offset+2 );
1367 proto_tree_add_item(item_tree, hf_enip_ucm_genstat,
1368 tvb, offset+2, 1, TRUE );
1370 /* Add additional status size */
1371 temp_data = tvb_get_guint8( tvb, offset+3 );
1372 proto_tree_add_text( item_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)", temp_data );
1374 add_stat_size = tvb_get_guint8( tvb, offset+3 )*2;
1378 /* Add additional status */
1379 pi = proto_tree_add_text( item_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
1381 for( i=0; i < add_stat_size/2; i ++ )
1383 proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
1387 /* If there is any command specific data create a sub-tree for it */
1388 if( ( item_length-4-add_stat_size ) != 0 )
1390 pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific data" );
1391 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1393 if( gen_stat == CI_GRC_SUCCESS )
1395 /* Success responses */
1397 if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN )
1399 /* Forward open Response (Success) */
1401 /* Display originator to target connection ID */
1402 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size );
1403 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1405 /* Display target to originator connection ID */
1406 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1407 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1409 /* Display connection serial number */
1410 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
1411 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", temp_data );
1413 /* Display the originator vendor id */
1414 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+10, 2, TRUE);
1416 /* Display the originator serial number */
1417 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
1418 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", temp_data );
1420 /* Display originator to target actual packet interval */
1421 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
1422 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 );
1424 /* Display originator to target actual packet interval */
1425 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
1426 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 );
1428 /* Display the application reply size */
1429 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
1430 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1432 /* Display the Reserved byte */
1433 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
1434 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
1436 if( app_rep_size != 0 )
1438 /* Display application Reply data */
1439 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
1441 for( i=0; i < app_rep_size; i++ )
1443 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
1444 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1447 } /* End of if reply data */
1449 } /* End of if forward open response */
1450 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE )
1452 /* Forward close response (Success) */
1454 /* Display connection serial number */
1455 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1456 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1458 /* Display the originator vendor id */
1459 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
1461 /* Display the originator serial number */
1462 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1463 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1465 /* Display the application reply size */
1466 app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
1467 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
1469 /* Display the Reserved byte */
1470 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1471 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
1473 if( app_rep_size != 0 )
1475 /* Display application Reply data */
1476 ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
1478 for( i=0; i < app_rep_size; i ++ )
1480 temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
1481 proto_item_append_text(ar_item, " 0x%02X", temp_byte );
1484 } /* End of if reply data */
1486 } /* End of if forward close response */
1487 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1489 /* Unconnected send response (Success) */
1491 /* Display service response data */
1492 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1494 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
1496 /* Multiple Service Reply (Success)*/
1498 /* Add number of replies */
1499 num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
1500 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
1503 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
1505 for( i=0; i < num_services; i++ )
1509 serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
1511 if( i == (num_services-1) )
1513 /* Last service to add */
1514 proto_item_append_text(temp_item, "%d", serv_offset );
1515 serv_length = item_length-add_stat_size-serv_offset-4;
1519 proto_item_append_text(temp_item, "%d, ", serv_offset );
1520 serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
1523 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
1524 temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1525 add_cip_data( temp_tree, tvb, offset+serv_offset+4, serv_length, pinfo );
1527 } /* End if Multiple service Packet */
1528 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
1530 /* Get Attribute List Reply (Success)*/
1534 /* Add Attribute Count */
1535 att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
1536 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
1539 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
1541 } /* End if Multiple service Packet */
1545 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1546 } /* end of check service code */
1551 /* Error responses */
1553 if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN ) ||
1554 ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE ) )
1556 /* Forward open and forward close error response look the same */
1558 /* Display connection serial number */
1559 temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
1560 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
1562 /* Display the originator vendor id */
1563 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
1565 /* Display the originator serial number */
1566 temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
1567 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
1569 /* Display remaining path size */
1570 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
1571 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
1573 /* Display reserved data */
1574 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
1575 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
1577 else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
1579 /* Unconnected send response (Unsuccess) */
1581 /* Display remaining path size */
1582 temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
1583 proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
1588 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
1591 } /* end of if-else( CI_CRC_SUCCESS ) */
1593 } /* End of if command-specific data present */
1595 } /* End of if reply */
1601 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
1602 proto_tree_add_text( item_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
1605 pi = proto_tree_add_text(item_tree, tvb, offset+2, req_path_size, "Request Path: ");
1606 show_epath( tvb, pi, offset+2, req_path_size );
1608 /* If there is any command specific data creat a sub-tree for it */
1609 if( (item_length-req_path_size-2) != 0 )
1612 pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
1613 cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
1615 /* Check what service code that recived */
1617 if( tvb_get_guint8( tvb, offset ) == SC_FWD_OPEN )
1619 /* Forward open Request*/
1621 /* Display the priority/tick timer */
1622 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1623 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1625 /* Display the time-out ticks */
1626 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1627 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1629 /* Display the actual time out */
1630 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1631 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1633 /* Display originator to taget connection ID */
1634 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
1635 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
1637 /* Display target to originator connection ID */
1638 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1639 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
1641 /* Display connection serial number */
1642 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
1643 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
1645 /* Display the originator vendor id */
1646 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+12, 2, TRUE);
1648 /* Display the originator serial number */
1649 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
1650 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
1652 /* Display the timeout multiplier */
1653 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
1654 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 );
1656 /* Put out an indicator for the reserved bytes */
1657 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
1659 /* Display originator to target requested packet interval */
1660 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
1661 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 );
1663 /* Display originator to target network connection patameterts, in a tree */
1664 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
1665 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 );
1666 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1668 /* Add the data to the tree */
1669 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
1670 tvb, offset+2+req_path_size+26, 2, TRUE );
1671 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
1672 tvb, offset+2+req_path_size+26, 2, TRUE );
1673 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
1674 tvb, offset+2+req_path_size+26, 2, TRUE );
1675 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
1676 tvb, offset+2+req_path_size+26, 2, TRUE );
1677 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
1678 tvb, offset+2+req_path_size+26, 2, TRUE );
1680 /* Display target to originator requested packet interval */
1681 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
1682 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 );
1684 /* Display target to originator network connection patameterts, in a tree */
1685 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
1686 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 );
1687 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1689 /* Add the data to the tree */
1690 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
1691 tvb, offset+2+req_path_size+32, 2, TRUE );
1692 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
1693 tvb, offset+2+req_path_size+32, 2, TRUE );
1694 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
1695 tvb, offset+2+req_path_size+32, 2, TRUE );
1696 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
1697 tvb, offset+2+req_path_size+32, 2, TRUE );
1698 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
1699 tvb, offset+2+req_path_size+32, 2, TRUE );
1701 /* Transport type/trigger in tree*/
1702 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
1704 ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
1705 ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
1707 /* Add the data to the tree */
1708 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_dir,
1709 tvb, offset+2+req_path_size+34, 1, TRUE );
1711 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_trigg,
1712 tvb, offset+2+req_path_size+34, 1, TRUE );
1714 proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_class,
1715 tvb, offset+2+req_path_size+34, 1, TRUE );
1718 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
1719 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1722 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
1723 show_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size );
1725 else if( tvb_get_guint8( tvb, offset ) == SC_FWD_CLOSE )
1727 /* Forward Close Request */
1729 /* Display the priority/tick timer */
1730 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1731 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1733 /* Display the time-out ticks */
1734 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1735 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1737 /* Display the actual time out */
1738 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1739 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1741 /* Display connection serial number */
1742 temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1743 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
1745 /* Display the originator vendor id */
1746 proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+4, 2, TRUE);
1748 /* Display the originator serial number */
1749 temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
1750 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
1752 /* Add the path size */
1753 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
1754 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
1756 /* Add the reserved byte */
1757 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
1758 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
1761 pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
1762 show_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size );
1764 } /* End of forward close */
1765 else if( tvb_get_guint8( tvb, offset ) == SC_UNCON_SEND )
1767 /* Unconnected send */
1769 /* Display the priority/tick timer */
1770 temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
1771 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
1773 /* Display the time-out ticks */
1774 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
1775 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
1777 /* Display the actual time out */
1778 temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
1779 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
1781 /* Message request size */
1782 msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
1783 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
1785 /* Message Request */
1786 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
1787 temp_tree = proto_item_add_subtree(temp_item, ett_mes_req );
1790 temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+4 );
1791 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 );
1793 /* Add service to info column */
1794 if(check_col(pinfo->cinfo, COL_INFO))
1796 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
1797 val_to_str( ( temp_data & 0x7F ),
1798 encap_sc_vals , ", Unknown Service (%x)") );
1801 /* MR - Request path Size */
1802 mr_req_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+5 )*2;
1803 proto_tree_add_text( temp_tree, tvb, offset+2+req_path_size+5, 1, "Request Path Size: %d (words)", mr_req_path_size/2 );
1806 temp_item = proto_tree_add_text(temp_tree, tvb, offset+2+req_path_size+6, mr_req_path_size, "Request Path: ");
1807 show_epath( tvb, temp_item, offset+2+req_path_size+6, mr_req_path_size );
1809 /* MR - Request data */
1810 if( ( msg_req_siz-2-mr_req_path_size ) != 0 )
1812 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: " );
1815 if( msg_req_siz % 2 )
1818 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
1819 tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
1820 msg_req_siz++; /* include the padding */
1823 /* Route Path Size */
1824 route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
1825 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 );
1828 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
1829 tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
1832 temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path");
1833 show_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size );
1835 } /* End if unconnected send */
1836 else if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
1838 /* Multiple service packet */
1840 /* Add number of services */
1841 num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
1842 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
1845 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
1847 for( i=0; i < num_services; i++ )
1851 serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
1853 if( i == (num_services-1) )
1855 /* Last service to add */
1856 serv_length = item_length-2-req_path_size-serv_offset;
1857 proto_item_append_text(temp_item, "%d", serv_offset );
1861 serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
1862 proto_item_append_text(temp_item, "%d, ", serv_offset );
1865 temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
1866 temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
1867 add_cip_data( temp_tree, tvb, offset+serv_offset+6, serv_length, pinfo );
1869 } /* End if Multiple service Packet */
1870 else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
1872 /* Get attribute list request */
1876 /* Add number of services */
1877 att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
1878 proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
1880 /* Add Attribute List */
1881 temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
1883 for( i=0; i < att_count; i++ )
1885 if( i == (att_count-1) )
1886 proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1888 proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
1891 } /* End of Get attribute list request */
1895 add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
1896 } /* End of check service code */
1898 } /* End of if command-specific data present */
1900 } /* end of if-else( request ) */
1902 } /* end of add_cip_data() */
1907 show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
1909 proto_item *temp_item, *ri, *ci;
1910 proto_item *sockaddr_item;
1911 proto_tree *temp_tree, *cip_tree, *item_tree, *sockaddr_tree;
1912 int temp_data, item_count, item_length, item, i;
1914 unsigned char name_length;
1916 /* Show Common Data Format sub tree */
1917 item_count = tvb_get_letohs( tvb, offset );
1918 ri = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
1919 cip_tree = proto_item_add_subtree(ri, ett_cip);
1921 while( item_count-- )
1923 /* Add item type tree */
1924 ci = proto_tree_add_item(cip_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
1925 item_tree = proto_item_add_subtree(ci, ett_cpf);
1927 /* Add length field */
1928 temp_data = tvb_get_letohs( tvb, offset+4 );
1929 proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", temp_data );
1931 item = tvb_get_letohs( tvb, offset+2 );
1932 item_length = tvb_get_letohs( tvb, offset+4 );
1936 /* Add item data field */
1940 case CONNECTION_BASED:
1942 /* Add Connection identifier */
1943 proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%08X", tvb_get_letohl( tvb, offset + 6 ) );
1945 /* Add Connection ID to Info col */
1946 if(check_col(pinfo->cinfo, COL_INFO))
1948 col_append_fstr(pinfo->cinfo, COL_INFO,
1950 tvb_get_letohl( tvb, offset+6 ) );
1955 case UNCONNECTED_MSG:
1957 /* Add CIP data tree*/
1958 add_cip_data( item_tree, tvb, offset+6, item_length, pinfo );
1962 case CONNECTION_TRANSPORT:
1964 if( encap_service == SEND_UNIT_DATA )
1967 ** If the encapsulation service is SendUnit Data, this is a
1968 ** encapsulated connected message
1971 /* Add sequence count ( Transport Class 1,2,3 )*/
1972 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Sequence Count: 0x%04X", tvb_get_letohs( tvb, offset+6 ) );
1974 /* Add CIP data tree */
1975 add_cip_data( item_tree, tvb, offset+8, item_length-2, pinfo );
1977 /* Add SEQ Count to Info col */
1980 if(check_col(pinfo->cinfo, COL_INFO))
1982 col_append_fstr(pinfo->cinfo, COL_INFO,
1984 tvb_get_letohs( tvb, offset+6 ) );
1991 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
1993 } /* End of if send unit data */
1998 case LIST_IDENTITY_RESP:
2000 /* Encapsulation version */
2001 temp_data = tvb_get_letohs( tvb, offset+6 );
2002 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
2004 /* Socket Address */
2005 sockaddr_item = proto_tree_add_text( item_tree, tvb, offset+8, 16, "Socket Address");
2006 sockaddr_tree = proto_item_add_subtree( sockaddr_item, ett_sockadd );
2008 /* Socket address struct - sin_family */
2009 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinfamily,
2010 tvb, offset+8, 2, FALSE );
2012 /* Socket address struct - sin_port */
2013 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinport,
2014 tvb, offset+10, 2, FALSE );
2016 /* Socket address struct - sin_address */
2017 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinaddr,
2018 tvb, offset+12, 4, FALSE );
2020 /* Socket address struct - sin_zero */
2021 proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinzero,
2022 tvb, offset+16, 8, FALSE );
2025 proto_tree_add_item(item_tree, hf_enip_vendors,
2026 tvb, offset+24, 2, TRUE );
2029 proto_tree_add_item(item_tree, hf_enip_cpf_lir_devtype,
2030 tvb, offset+26, 2, TRUE );
2033 proto_tree_add_item(item_tree, hf_enip_cpf_lir_prodcode,
2034 tvb, offset+28, 2, TRUE );
2037 temp_data = tvb_get_letohs( tvb, offset+30 );
2038 proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: v.%d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
2041 proto_tree_add_item(item_tree, hf_enip_cpf_lir_status,
2042 tvb, offset+32, 2, TRUE );
2045 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sernbr,
2046 tvb, offset+34, 4, TRUE );
2048 /* Product Name Length */
2049 proto_tree_add_item(item_tree, hf_enip_cpf_lir_namelength,
2050 tvb, offset+38, 1, TRUE );
2052 /* Get the lenth of the name */
2053 name_length = tvb_get_guint8( tvb, offset+38 );
2055 /* Product Name Length */
2056 proto_tree_add_item(item_tree, hf_enip_cpf_lir_name,
2057 tvb, offset+39, name_length, TRUE );
2059 /* Product Name Length */
2060 proto_tree_add_item(item_tree, hf_enip_cpf_lir_state,
2061 tvb, offset+name_length+39, 1, TRUE );
2065 case SOCK_ADR_INFO_OT:
2066 case SOCK_ADR_INFO_TO:
2068 /* Socket address struct - sin_family */
2069 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinfamily,
2070 tvb, offset+6, 2, FALSE );
2072 /* Socket address struct - sin_port */
2073 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinport,
2074 tvb, offset+8, 2, FALSE );
2076 /* Socket address struct - sin_address */
2077 proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinaddr,
2078 tvb, offset+10, 4, FALSE );
2080 /* Socket address struct - sin_zero */
2081 proto_tree_add_item( item_tree, hf_enip_cpf_lir_sinzero,
2082 tvb, offset+14, 8, FALSE );
2087 proto_tree_add_item(item_tree, hf_enip_cpf_sat_connid,
2088 tvb, offset+6, 4, TRUE );
2090 proto_tree_add_item(item_tree, hf_enip_cpf_sat_seqnum,
2091 tvb, offset+10, 4, TRUE );
2093 /* Add info to column */
2095 if(check_col(pinfo->cinfo, COL_INFO))
2097 col_clear(pinfo->cinfo, COL_INFO);
2099 col_add_fstr(pinfo->cinfo, COL_INFO,
2100 "Connection: ID=0x%08X, SEQ=%010d",
2101 tvb_get_letohl( tvb, offset+6 ),
2102 tvb_get_letohl( tvb, offset+10 ) );
2107 case LIST_SERVICES_RESP:
2109 /* Encapsulation version */
2110 temp_data = tvb_get_letohs( tvb, offset+6 );
2111 proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
2113 /* Capability flags */
2114 temp_data = tvb_get_letohs( tvb, offset+8 );
2115 temp_item = proto_tree_add_text(item_tree, tvb, offset+8, 2, "Capability Flags: 0x%04X", temp_data );
2116 temp_tree = proto_item_add_subtree(temp_item, ett_lsrcf);
2118 proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_tcp,
2119 tvb, offset+8, 2, TRUE );
2120 proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_udp,
2121 tvb, offset+8, 2, TRUE );
2123 /* Name of service */
2124 temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name Of Service: " );
2126 for( i=0; i<16; i++ )
2128 temp_char = tvb_get_guint8( tvb, offset+10+i );
2130 if( temp_char == 0 )
2133 proto_item_append_text(temp_item, "%c", temp_char );
2140 add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
2143 } /* end of switch( item type ) */
2145 } /* end of if( item length ) */
2147 offset = offset + item_length + 4;
2149 } /* end of while( item count ) */
2151 } /* end of show_cdf() */
2156 classify_packet(packet_info *pinfo)
2158 /* see if nature of packets can be derived from src/dst ports */
2159 /* if so, return as found */
2160 if ( ( ENIP_ENCAP_PORT == pinfo->srcport && ENIP_ENCAP_PORT != pinfo->destport ) ||
2161 ( ENIP_ENCAP_PORT != pinfo->srcport && ENIP_ENCAP_PORT == pinfo->destport ) ) {
2162 if ( ENIP_ENCAP_PORT == pinfo->srcport )
2163 return RESPONSE_PACKET;
2164 else if ( ENIP_ENCAP_PORT == pinfo->destport )
2165 return REQUEST_PACKET;
2167 /* else, cannot classify */
2168 return CANNOT_CLASSIFY;
2172 get_cipencap_pdu_len(tvbuff_t *tvb, int offset)
2177 * Get the length of the data from the encapsulation header.
2179 plen = tvb_get_letohs(tvb, offset + 2);
2182 * That length doesn't include the encapsulation header itself;
2188 /* Code to actually dissect the packets */
2190 dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2193 guint16 encap_cmd, encap_data_length;
2194 char pkt_type_str[9] = "";
2197 /* Set up structures needed to add the protocol subtree and manage it */
2198 proto_item *ti, *encaph, *csf;
2199 proto_tree *cipencap_tree, *headertree, *csftree;
2201 /* Make entries in Protocol column and Info column on summary display */
2202 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2203 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
2204 if (check_col(pinfo->cinfo, COL_INFO))
2205 col_clear(pinfo->cinfo, COL_INFO);
2207 encap_cmd = tvb_get_letohs( tvb, 0 );
2209 if( check_col(pinfo->cinfo, COL_INFO) )
2211 packet_type = classify_packet(pinfo);
2213 switch ( packet_type )
2215 case REQUEST_PACKET:
2216 strcpy(pkt_type_str, "Req");
2219 case RESPONSE_PACKET:
2220 strcpy(pkt_type_str, "Rsp");
2224 strcpy(pkt_type_str, "?");
2227 /* Add service and request/response to info column */
2228 col_add_fstr(pinfo->cinfo, COL_INFO,
2230 val_to_str(encap_cmd, encap_cmd_vals, "Unknown (0x%04x)"),
2234 } /* end of if( col exists ) */
2236 /* In the interest of speed, if "tree" is NULL, don't do any work not
2237 necessary to generate protocol tree items. */
2240 /* create display subtree for the protocol */
2241 ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
2243 cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
2245 /* Add encapsulation header tree */
2246 encaph = proto_tree_add_text( cipencap_tree, tvb, 0, 24, "Encapsulation Header");
2247 headertree = proto_item_add_subtree(encaph, ett_cipencaph);
2249 /* CIP header information */
2250 proto_tree_add_uint(headertree, hf_enip_command, tvb, 0, 2, encap_cmd);
2252 encap_data_length = tvb_get_letohs( tvb, 2 );
2253 proto_tree_add_text( headertree, tvb, 2, 2, "Length: %u", encap_data_length );
2255 proto_tree_add_text( headertree, tvb, 4, 4, "Session Handle: 0x%08X",
2256 tvb_get_letohl( tvb, 4 ) );
2258 status = tvb_get_letohl( tvb, 8 );
2259 proto_tree_add_text( headertree, tvb, 8, 4, "Status: %s (0x%08X)",
2260 val_to_str( status, encap_status_vals,
2261 "Unknown Status Code" ),
2264 add_byte_array_text_to_proto_tree( headertree, tvb, 12, 8, "Sender context: " );
2266 proto_tree_add_text( headertree, tvb, 20, 4, "Options: 0x%08X",
2267 tvb_get_letohl( tvb, 20 ) );
2270 ** For some commands we want to add some info to the info column
2273 if( check_col( pinfo->cinfo, COL_INFO ) )
2278 case REGISTER_SESSION:
2279 case UNREGISTER_SESSION:
2280 col_append_fstr( pinfo->cinfo, COL_INFO, ", Session: 0x%08X",
2281 tvb_get_letohl( tvb, 4 ) );
2283 } /* end of switch() */
2285 } /* end of id info column */
2287 /* Command specific data - create tree */
2288 if( encap_data_length )
2290 /* The packet have some command specific data, buid a sub tree for it */
2292 csf = proto_tree_add_text( cipencap_tree, tvb, 24, encap_data_length,
2293 "Command Specific Data");
2295 csftree = proto_item_add_subtree(csf, ett_csf);
2303 show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2307 show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2310 case LIST_INTERFACES:
2311 show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
2314 case REGISTER_SESSION:
2315 proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X",
2316 tvb_get_letohs( tvb, 24 ) );
2318 proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X",
2319 tvb_get_letohs( tvb, 26 ) );
2323 case UNREGISTER_SESSION:
2327 case SEND_UNIT_DATA:
2328 proto_tree_add_item(csftree, hf_enip_ifacehnd, tvb, 24, 4, TRUE);
2330 proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
2331 tvb_get_letohs( tvb, 28 ) );
2333 show_cdf( encap_cmd, tvb, pinfo, csftree, 30 );
2336 case INDICATE_STATUS:
2340 /* Can not decode - Just show the data */
2341 add_byte_array_text_to_proto_tree( headertree, tvb, 24, encap_data_length, "Encap Data: " );
2344 } /* end of switch() */
2346 } /* end of if( encapsulated data ) */
2349 } /* end of dissect_cipencap() */
2352 dissect_cipencap_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2356 /* An ENIP packet is at least 4 bytes long - we need the command type. */
2357 if (!tvb_bytes_exist(tvb, 0, 4))
2360 /* Get the command type and see if it's valid. */
2361 encap_cmd = tvb_get_letohs( tvb, 0 );
2362 if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
2363 return 0; /* not a known command */
2365 dissect_cipencap_pdu(tvb, pinfo, tree);
2366 return tvb_length(tvb);
2370 dissect_cipencap_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2374 /* An ENIP packet is at least 4 bytes long - we need the command type. */
2375 if (!tvb_bytes_exist(tvb, 0, 4))
2378 /* Get the command type and see if it's valid. */
2379 encap_cmd = tvb_get_letohs( tvb, 0 );
2380 if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
2381 return 0; /* not a known command */
2383 tcp_dissect_pdus(tvb, pinfo, tree, cipencap_desegment, 4,
2384 get_cipencap_pdu_len, dissect_cipencap_pdu);
2385 return tvb_length(tvb);
2388 /* Code to actually dissect the io packets*/
2390 dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2392 /* Set up structures needed to add the protocol subtree and manage it */
2394 proto_tree *cipencap_tree;
2396 /* Make entries in Protocol column and Info column on summary display */
2397 if (check_col(pinfo->cinfo, COL_PROTOCOL))
2398 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
2400 /* In the interest of speed, if "tree" is NULL, don't do any work not
2401 necessary to generate protocol tree items. */
2404 /* create display subtree for the protocol */
2405 ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
2407 cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
2409 show_cdf( 0xFFFF, tvb, pinfo, cipencap_tree, 0 );
2412 } /* end of dissect_enipio() */
2415 /* Register the protocol with Ethereal */
2417 /* this format is require because a script is used to build the C function
2418 that calls all the protocol registration.
2422 proto_register_cipencap(void)
2425 /* Setup list of header fields lengthSee Section 1.6.1 for details*/
2426 static hf_register_info hf[] = {
2428 { "Command", "enip.command",
2429 FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
2430 "Encapsulation command", HFILL }
2433 /* Encapsulated data headers */
2434 /* Common Packet Format */
2435 { &hf_enip_cpf_typeid,
2436 { "Type ID", "enip.cpf.typeid",
2437 FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
2438 "Type of encapsulated item", HFILL }
2442 { &hf_enip_ifacehnd,
2443 { "Interface Handle", "enip.cpf.rr.ifacehnd",
2444 FT_UINT32, BASE_HEX, NULL, 0,
2445 "Interface handle", HFILL }
2448 /* Unconnected message */
2450 { "Request/Response", "enip.cip.rr",
2451 FT_UINT8, BASE_HEX, VALS(encap_sc_rr), 0x80,
2452 "Request or Response message", HFILL }
2455 { "Service", "enip.cip.sc",
2456 FT_UINT8, BASE_HEX, VALS(encap_sc_vals), 0x7F,
2457 "CIP Service code", HFILL }
2459 { &hf_enip_ucm_path,
2460 { "Request Path", "enip.cip.path",
2461 FT_BYTES, BASE_HEX, NULL, 0,
2462 "Request path", HFILL }
2464 { &hf_enip_ucm_genstat,
2465 { "General Status", "enip.cip.genstat",
2466 FT_UINT8, BASE_HEX, VALS(encap_cip_gs_vals), 0,
2467 "General Status", HFILL }
2470 /* List identity response */
2471 { &hf_enip_cpf_lir_sinfamily,
2472 { "sin_family", "enip.lir.sinfamily",
2473 FT_UINT16, BASE_DEC, NULL, 0,
2474 "Socket Address Sin Family", HFILL }
2476 { &hf_enip_cpf_lir_sinport,
2477 { "sin_port", "enip.lir.sinport",
2478 FT_UINT16, BASE_DEC, NULL, 0,
2479 "Socket Address Sin Port", HFILL }
2481 { &hf_enip_cpf_lir_sinaddr,
2482 { "sin_addr", "enip.lir.sinaddr",
2483 FT_IPv4, BASE_HEX, NULL, 0,
2484 "Socket Address Sin Addr", HFILL }
2486 { &hf_enip_cpf_lir_sinzero,
2487 { "sin_zero", "enip.lir.sinzero",
2488 FT_BYTES, BASE_HEX, NULL, 0,
2489 "Socket Address Sin Zero", HFILL }
2491 { &hf_enip_cpf_lir_devtype,
2492 { "Device Type", "enip.lir.devtype",
2493 FT_UINT16, BASE_DEC, VALS(encap_cip_devtype_vals), 0,
2494 "Device Type", HFILL }
2496 { &hf_enip_cpf_lir_prodcode,
2497 { "Product Code", "enip.lir.prodcode",
2498 FT_UINT16, BASE_DEC, NULL, 0,
2499 "Product Code", HFILL }
2501 { &hf_enip_cpf_lir_status,
2502 { "Status", "enip.lir.status",
2503 FT_UINT16, BASE_HEX, NULL, 0,
2506 { &hf_enip_cpf_lir_sernbr,
2507 { "Serial Number", "enip.lir.ser",
2508 FT_UINT32, BASE_HEX, NULL, 0,
2509 "Serial Number", HFILL }
2511 { &hf_enip_cpf_lir_namelength,
2512 { "Product Name Length", "enip.lir.namelength",
2513 FT_UINT8, BASE_DEC, NULL, 0,
2514 "Product Name Length", HFILL }
2516 { &hf_enip_cpf_lir_name,
2517 { "Product Name", "enip.lir.name",
2518 FT_STRING, BASE_NONE, NULL, 0,
2519 "Product Name", HFILL }
2521 { &hf_enip_cpf_lir_state,
2522 { "State", "enip.lir.state",
2523 FT_UINT8, BASE_HEX, NULL, 0,
2526 /* Vendor ID number */
2528 { "Vendor ID", "enip.vnd",
2529 FT_UINT16, BASE_HEX, VALS(encap_cip_vendor_vals), 0,
2530 "Vendor ID number", HFILL }
2532 { &hf_enip_ucm_fwo_comp,
2533 { "Compatibility", "enip.cip.fwo.cmp",
2534 FT_UINT8, BASE_HEX, VALS(enip_com_bit_vals), 0x80,
2535 "Compatibility bit", HFILL }
2537 { &hf_enip_ucm_fwo_mrev,
2538 { "Major Revision", "enip.cip.fwo.mrev",
2539 FT_UINT8, BASE_DEC, NULL, 0x7F,
2540 "Major Revision", HFILL }
2542 { &hf_enip_ucm_fwo_con_size,
2543 { "Connection Size", "enip.cip.fwo.consize",
2544 FT_UINT16, BASE_DEC, NULL, 0x01FF,
2545 "Connection size", HFILL }
2547 { &hf_enip_ucm_fwo_fixed_var,
2548 { "Connection Size Type", "enip.cip.fwo.f_v",
2549 FT_UINT16, BASE_DEC, VALS(enip_con_fw_vals), 0x0200,
2550 "Fixed or variable connection size", HFILL }
2552 { &hf_enip_ucm_fwo_prio,
2553 { "Priority", "enip.cip.fwo.prio",
2554 FT_UINT16, BASE_DEC, VALS(enip_con_prio_vals), 0x0C00,
2555 "Connection priority", HFILL }
2557 { &hf_enip_ucm_fwo_typ,
2558 { "Connection Type", "enip.cip.fwo.typ",
2559 FT_UINT16, BASE_DEC, VALS(enip_con_type_vals), 0x6000,
2560 "Connection type", HFILL }
2562 { &hf_enip_ucm_fwo_own,
2563 { "Owner", "enip.cip.fwo.own",
2564 FT_UINT16, BASE_DEC, VALS(enip_con_owner_vals), 0x8000,
2565 "Redundant owner bit", HFILL }
2567 { &hf_enip_ucm_fwo_dir,
2568 { "Direction", "enip.cip.fwo.dir",
2569 FT_UINT8, BASE_DEC, VALS(enip_con_dir_vals), 0x80,
2570 "Direction", HFILL }
2572 { &hf_enip_ucm_fwo_trigg,
2573 { "Trigger", "enip.cip.fwo.trigg",
2574 FT_UINT8, BASE_DEC, VALS(enip_con_trigg_vals), 0x70,
2575 "Production trigger", HFILL }
2577 { &hf_enip_ucm_fwo_class,
2578 { "Class", "enip.cip.fwo.class",
2579 FT_UINT8, BASE_DEC, VALS(enip_con_class_vals), 0x0F,
2580 "Transport Class", HFILL }
2582 /* Sequenced Address Type */
2583 { &hf_enip_cpf_sat_connid,
2584 { "Connection ID", "enip.sat.connid",
2585 FT_UINT32, BASE_HEX, NULL, 0,
2586 "Connection ID from forward open reply", HFILL }
2588 { &hf_enip_cpf_sat_seqnum,
2589 { "Sequence Number", "enip.sat.seq",
2590 FT_UINT32, BASE_DEC, NULL, 0,
2591 "Sequence Number", HFILL }
2593 { &hf_enip_cpf_lsr_tcp,
2594 { "Supports CIP Encapsultion via TCP", "enip.ls.tcp",
2595 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
2596 "Supports CIP Encapsultion via TCP", HFILL }
2598 { &hf_enip_cpf_lsr_udp,
2599 { "Supports CIP Class 0 or 1 via UDP", "enip.ls.udp",
2600 FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
2601 "Supports CIP Class 0 or 1 via UDP", HFILL }
2607 /* Setup protocol subtree array */
2608 static gint *ett[] = {
2628 module_t *cipencap_module;
2630 /* Register the protocol name and description */
2631 proto_cipencap = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
2634 /* Required function calls to register the header fields and subtrees used */
2635 proto_register_field_array(proto_cipencap, hf, array_length(hf));
2636 proto_register_subtree_array(ett, array_length(ett));
2638 cipencap_module = prefs_register_protocol(proto_cipencap, NULL);
2639 prefs_register_bool_preference(cipencap_module, "desegment",
2640 "Desegment all EtherNet/IP messages spanning multiple TCP segments",
2641 "Whether the EtherNet/IP dissector should desegment all messages spanning multiple TCP segments",
2642 &cipencap_desegment);
2643 } /* end of proto_register_cipencap() */
2646 /* If this dissector uses sub-dissector registration add a registration routine.
2647 This format is required because a script is used to find these routines and
2648 create the code that calls these routines.
2651 proto_reg_handoff_cipencap(void)
2653 dissector_handle_t cipencap_udp_handle, cipencap_tcp_handle;
2654 dissector_handle_t enipio_handle;
2656 /* Register for encapsulated CIP data, using both TCP/UDP */
2657 cipencap_tcp_handle = new_create_dissector_handle(dissect_cipencap_tcp, proto_cipencap);
2658 dissector_add("tcp.port", ENIP_ENCAP_PORT, cipencap_tcp_handle);
2659 cipencap_udp_handle = new_create_dissector_handle(dissect_cipencap_udp, proto_cipencap);
2660 dissector_add("udp.port", ENIP_ENCAP_PORT, cipencap_udp_handle);
2662 /* Register for IO data over UDP */
2663 enipio_handle = create_dissector_handle(dissect_enipio, proto_cipencap);
2664 dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
2666 } /* end of proto_reg_handoff_cipencap() */